!10521 posenet add front camera and styletransfer save

From: @sishuikang
Reviewed-by: @zhanghaibo5,@ivss
Signed-off-by: @zhanghaibo5
This commit is contained in:
mindspore-ci-bot 2020-12-26 14:46:43 +08:00 committed by Gitee
commit b97efc9da2
46 changed files with 1070 additions and 878 deletions

View File

@ -8,8 +8,8 @@ android {
applicationId "com.mindspore.himindspore"
minSdkVersion 21
targetSdkVersion 30
versionCode 4
versionName "1.1.2"
versionCode 5
versionName "1.1.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions {

View File

@ -292,7 +292,7 @@ public class SplashActivity extends BaseActivity<MainPresenter> implements MainC
public void showUpdate(final UpdateInfoBean updateInfo) {
if (now_version == updateInfo.getVersionCode()) {
Toast.makeText(this, "已经是最新版本", Toast.LENGTH_SHORT).show();
// Toast.makeText(this, "已经是最新版本", Toast.LENGTH_SHORT).show();
Log.d(TAG + "版本号是", "onResponse: " + now_version);
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);

View File

@ -1,23 +0,0 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mindspore.posenet;
import android.media.Image;
import android.view.SurfaceView;
public interface CameraDataDealListener {
void dataDeal(Image image, SurfaceView surfaceView);
}

View File

@ -15,12 +15,17 @@
*/
package com.mindspore.posenet;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
@ -41,33 +46,54 @@ import android.view.Surface;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.util.Pair;
import androidx.fragment.app.Fragment;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import static com.mindspore.posenet.Posenet.BodyPart.LEFT_ANKLE;
import static com.mindspore.posenet.Posenet.BodyPart.LEFT_ELBOW;
import static com.mindspore.posenet.Posenet.BodyPart.LEFT_HIP;
import static com.mindspore.posenet.Posenet.BodyPart.LEFT_KNEE;
import static com.mindspore.posenet.Posenet.BodyPart.LEFT_SHOULDER;
import static com.mindspore.posenet.Posenet.BodyPart.LEFT_WRIST;
import static com.mindspore.posenet.Posenet.BodyPart.RIGHT_ANKLE;
import static com.mindspore.posenet.Posenet.BodyPart.RIGHT_ELBOW;
import static com.mindspore.posenet.Posenet.BodyPart.RIGHT_HIP;
import static com.mindspore.posenet.Posenet.BodyPart.RIGHT_KNEE;
import static com.mindspore.posenet.Posenet.BodyPart.RIGHT_SHOULDER;
import static com.mindspore.posenet.Posenet.BodyPart.RIGHT_WRIST;
/**
* A simple {@link Fragment} subclass.
* create an instance of this fragment.
*/
public class PoseNetFragment extends Fragment {
private final static int REQUEST_CAMERA_PERMISSION = 1;
private String cameraId = "1";
private final List bodyJoints = Arrays.asList(
new Pair(LEFT_WRIST, LEFT_ELBOW), new Pair(LEFT_ELBOW, LEFT_SHOULDER),
new Pair(LEFT_SHOULDER, RIGHT_SHOULDER), new Pair(RIGHT_SHOULDER, RIGHT_ELBOW),
new Pair(RIGHT_ELBOW, RIGHT_WRIST), new Pair(LEFT_SHOULDER, LEFT_HIP),
new Pair(LEFT_HIP, RIGHT_HIP), new Pair(RIGHT_HIP, RIGHT_SHOULDER),
new Pair(LEFT_HIP, LEFT_KNEE), new Pair(LEFT_KNEE, LEFT_ANKLE),
new Pair(RIGHT_HIP, RIGHT_KNEE), new Pair(RIGHT_KNEE, RIGHT_ANKLE));
private static final String TAG = "PoseNetFragment";
private int mCameraId = CameraCharacteristics.LENS_FACING_FRONT; // 要打开的摄像头ID
private SurfaceView surfaceView;
private CameraCaptureSession captureSession;
private CameraDevice cameraDevice;
private Size previewSize;
private int previewWidth;
private int previewHeight;
private final int PREVIEW_WIDTH = 640;
private final int PREVIEW_HEIGHT = 480;
private final static int PREVIEW_WIDTH = 640;
private final static int PREVIEW_HEIGHT = 480;
private Size previewSize = new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT);
private HandlerThread backgroundThread;
private Handler backgroundHandler;
private ImageReader imageReader;
@ -76,8 +102,18 @@ public class PoseNetFragment extends Fragment {
private Semaphore cameraOpenCloseLock = new Semaphore(1);//使用信号量 Semaphore 进行多线程任务调度
private boolean flashSupported;
/**
* Model input shape for images.
*/
private final static int MODEL_WIDTH = 257;
private final static int MODEL_HEIGHT = 257;
private static final String TAG = "PoseNetFragment";
private final double minConfidence = 0.5;
private final float circleRadius = 8.0f;
private Paint paint = new Paint();
private Posenet posenet;
private int[] rgbBytes = new int[PREVIEW_WIDTH * PREVIEW_HEIGHT];
private byte[][] yuvBytes = new byte[3][];
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@ -93,12 +129,14 @@ public class PoseNetFragment extends Fragment {
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
cameraOpenCloseLock.release();
cameraDevice.close();
closeCamera();
PoseNetFragment.this.cameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
onDisconnected(cameraDevice);
closeCamera();
Activity activity = getActivity();
if (activity != null) {
activity.finish();
@ -106,7 +144,6 @@ public class PoseNetFragment extends Fragment {
}
};
private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
@ -119,12 +156,6 @@ public class PoseNetFragment extends Fragment {
}
};
private CameraDataDealListener cameraDataDealListener;
public void setCameraDataDealListener(CameraDataDealListener cameraDataDealListener) {
this.cameraDataDealListener = cameraDataDealListener;
}
public static PoseNetFragment newInstance() {
PoseNetFragment fragment = new PoseNetFragment();
return fragment;
@ -155,86 +186,24 @@ public class PoseNetFragment extends Fragment {
openCamera();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
posenet = new Posenet(getActivity());
}
public void onPause() {
this.closeCamera();
this.stopBackgroundThread();
super.onPause();
}
public void onDestroy() {
super.onDestroy();
}
private void requestCameraPermission() {
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
Toast.makeText(getContext(), "This app needs camera permission.", Toast.LENGTH_LONG).show();
} else {
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (allPermissionsGranted(grantResults)) {
Toast.makeText(getContext(), "This app needs camera permission.", Toast.LENGTH_LONG).show();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private boolean allPermissionsGranted(int[] grantResults) {
for (int grantResult : grantResults) {
if (grantResult == PackageManager.PERMISSION_DENIED) {
return false;
}
}
return true;
}
/**
* Sets up member variables related to camera.
*/
private void setUpCameraOutputs() {
CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
// We don't use a front facing camera in this sample.
Integer cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING);
if (cameraDirection != null && cameraDirection == CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
previewSize = new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT);
imageReader = ImageReader.newInstance(
PREVIEW_WIDTH, PREVIEW_HEIGHT,
ImageFormat.YUV_420_888, /*maxImages*/ 2
);
previewHeight = previewSize.getHeight();
previewWidth = previewSize.getWidth();
// Initialize the storage bitmaps once when the resolution is known.
// Check if the flash is supported.
flashSupported =
characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) == true;
this.cameraId = cameraId;
// We've found a viable camera and finished setting up member variables,
// so we don't need to iterate through other available cameras.
return;
}
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
public void switchCamera() {
mCameraId ^= 1;
Log.d(TAG, "switchCamera: mCameraId: " + mCameraId);
closeCamera();
openCamera();
}
/**
@ -242,17 +211,23 @@ public class PoseNetFragment extends Fragment {
*/
@SuppressLint("MissingPermission")
private void openCamera() {
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
this.requestCameraPermission();
}
setUpCameraOutputs();
CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(Integer.toString(mCameraId));
previewSize = new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT);
imageReader = ImageReader.newInstance(
PREVIEW_WIDTH, PREVIEW_HEIGHT,
ImageFormat.YUV_420_888, /*maxImages*/ 2
);
imageReader.setOnImageAvailableListener(imageAvailableListener, backgroundHandler);
// Check if the flash is supported.
flashSupported =
characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) == true;
// Wait for camera to open - 2.5 seconds is sufficient
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
manager.openCamera(cameraId, mStateCallback, backgroundHandler);
manager.openCamera(Integer.toString(mCameraId), mStateCallback, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
@ -305,31 +280,48 @@ public class PoseNetFragment extends Fragment {
}
}
private final ImageReader.OnImageAvailableListener imageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
if (previewWidth != 0 && previewHeight != 0 && imageReader != null) {
if (imageReader != null) {
Image image = imageReader.acquireLatestImage();
if (cameraDataDealListener != null) {
cameraDataDealListener.dataDeal(image, surfaceView);
if (image == null || image.getPlanes() == null) {
return;
}
fillBytes(image.getPlanes(), yuvBytes);
ImageUtils.convertYUV420ToARGB8888(yuvBytes[0], yuvBytes[1], yuvBytes[2],
PREVIEW_WIDTH, PREVIEW_HEIGHT,
image.getPlanes()[0].getRowStride(),
image.getPlanes()[1].getRowStride(),
image.getPlanes()[1].getPixelStride(),
rgbBytes);
Bitmap imageBitmap = Bitmap.createBitmap(
rgbBytes, PREVIEW_WIDTH, PREVIEW_HEIGHT,
Bitmap.Config.ARGB_8888);
Matrix rotateMatrix = new Matrix();
if (mCameraId == CameraCharacteristics.LENS_FACING_FRONT) {
rotateMatrix.postRotate(90.0f);
} else if (mCameraId == CameraCharacteristics.LENS_FACING_BACK) {
rotateMatrix.postRotate(270.0f);
rotateMatrix.postScale(-1.0f, 1.0f);
}
Bitmap rotatedBitmap = Bitmap.createBitmap(
imageBitmap, 0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT,
rotateMatrix, true
);
processImage(rotatedBitmap);
image.close();
}
}
};
/**
* Creates a new [CameraCaptureSession] for camera preview.
*/
private void createCameraPreviewSession() {
try {
// We capture images from preview in YUV format.
imageReader = ImageReader.newInstance(
previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2);
imageReader.setOnImageAvailableListener(imageAvailableListener, backgroundHandler);
// This is the surface we need to record images for processing.
Surface recordingSurface = imageReader.getSurface();
@ -387,4 +379,136 @@ public class PoseNetFragment extends Fragment {
}
}
/**
* Fill the yuvBytes with data from image planes.
*/
private void fillBytes(Image.Plane[] planes, byte[][] yuvBytes) {
// Row stride is the total number of bytes occupied in memory by a row of an image.
// Because of the variable row stride it's not possible to know in
// advance the actual necessary dimensions of the yuv planes
for (int i = 0; i < planes.length; ++i) {
ByteBuffer buffer = planes[i].getBuffer();
if (yuvBytes[i] == null) {
yuvBytes[i] = new byte[buffer.capacity()];
}
buffer.get(yuvBytes[i]);
}
}
/**
* Crop Bitmap to maintain aspect ratio of model input.
*/
private Bitmap cropBitmap(Bitmap bitmap) {
float bitmapRatio = bitmap.getHeight() / bitmap.getWidth();
float modelInputRatio = MODEL_HEIGHT / MODEL_WIDTH;
double maxDifference = 1.0E-5D;
float cropHeight = modelInputRatio - bitmapRatio;
if (Math.abs(cropHeight) < maxDifference) {
return bitmap;
} else {
Bitmap croppedBitmap;
if (modelInputRatio < bitmapRatio) {
cropHeight = (float) bitmap.getHeight() - (float) bitmap.getWidth() / modelInputRatio;
croppedBitmap = Bitmap.createBitmap(bitmap,
0, (int) (cropHeight / 2), bitmap.getWidth(), (int) (bitmap.getHeight() - cropHeight));
} else {
cropHeight = (float) bitmap.getWidth() - (float) bitmap.getHeight() * modelInputRatio;
croppedBitmap = Bitmap.createBitmap(bitmap,
(int) (cropHeight / 2), 0, (int) (bitmap.getWidth() - cropHeight), bitmap.getHeight());
}
return croppedBitmap;
}
}
/**
* Set the paint color and size.
*/
private void setPaint() {
paint.setColor(getResources().getColor(R.color.posenet_text_blue));
paint.setTextSize(80.0f);
paint.setStrokeWidth(8.0f);
}
/**
* Draw bitmap on Canvas.
*/
private void draw(Canvas canvas, Posenet.Person person, Bitmap bitmap) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// Draw `bitmap` and `person` in square canvas.
int screenWidth, screenHeight;
int left, right, top, bottom;
if (canvas.getHeight() > canvas.getWidth()) {
screenWidth = canvas.getWidth();
screenHeight = canvas.getWidth();
left = 0;
top = (canvas.getHeight() - canvas.getWidth()) / 2;
} else {
screenWidth = canvas.getHeight();
screenHeight = canvas.getHeight();
left = (canvas.getWidth() - canvas.getHeight()) / 2;
top = 0;
}
right = left + screenWidth;
bottom = top + screenHeight;
setPaint();
canvas.drawBitmap(
bitmap,
new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()),
new Rect(left, top, right, bottom), paint);
float widthRatio = (float) screenWidth / MODEL_WIDTH;
float heightRatio = (float) screenHeight / MODEL_HEIGHT;
for (Posenet.KeyPoint keyPoint : person.keyPoints) {
if (keyPoint.score > minConfidence) {
Posenet.Position position = keyPoint.position;
float adjustedX = position.x * widthRatio + left;
float adjustedY = position.y * heightRatio + top;
canvas.drawCircle(adjustedX, adjustedY, circleRadius, paint);
}
}
for (int i = 0; i < bodyJoints.size(); i++) {
Pair line = (Pair) bodyJoints.get(i);
Posenet.BodyPart first = (Posenet.BodyPart) line.first;
Posenet.BodyPart second = (Posenet.BodyPart) line.second;
if (person.keyPoints.get(first.ordinal()).score > minConfidence &
person.keyPoints.get(second.ordinal()).score > minConfidence) {
canvas.drawLine(
person.keyPoints.get(first.ordinal()).position.x * widthRatio + left,
person.keyPoints.get(first.ordinal()).position.y * heightRatio + top,
person.keyPoints.get(second.ordinal()).position.x * widthRatio + left,
person.keyPoints.get(second.ordinal()).position.y * heightRatio + top, paint);
}
}
canvas.drawText(String.format("Score: %.2f", person.score),
(15.0f * widthRatio), (30.0f * heightRatio + bottom), paint);
canvas.drawText(String.format("Time: %.2f ms", posenet.lastInferenceTimeNanos * 1.0f / 1_000_000),
(15.0f * widthRatio), (50.0f * heightRatio + bottom), paint
);
// Draw!
surfaceView.getHolder().unlockCanvasAndPost(canvas);
}
/**
* Process image using Posenet library.
*/
private void processImage(Bitmap bitmap) {
// Crop bitmap.
Bitmap croppedBitmap = cropBitmap(bitmap);
// Created scaled version of bitmap for model input.
Bitmap scaledBitmap = Bitmap.createScaledBitmap(croppedBitmap, MODEL_WIDTH, MODEL_HEIGHT, true);
// Perform inference.
Posenet.Person person = posenet.estimateSinglePose(scaledBitmap);
Canvas canvas = surfaceView.getHolder().lockCanvas();
draw(canvas, person, scaledBitmap);
}
}

View File

@ -15,6 +15,10 @@
*/
package com.mindspore.posenet;
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@ -24,10 +28,19 @@ import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.hardware.camera2.CameraCharacteristics;
import android.media.Image;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.SurfaceView;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.util.Pair;
import com.alibaba.android.arouter.facade.annotation.Route;
@ -50,213 +63,114 @@ import static com.mindspore.posenet.Posenet.BodyPart.RIGHT_SHOULDER;
import static com.mindspore.posenet.Posenet.BodyPart.RIGHT_WRIST;
@Route(path = "/posenet/PosenetMainActivity")
public class PosenetMainActivity extends AppCompatActivity implements CameraDataDealListener {
public class PosenetMainActivity extends AppCompatActivity {
private final List bodyJoints = Arrays.asList(
new Pair(LEFT_WRIST, LEFT_ELBOW), new Pair(LEFT_ELBOW, LEFT_SHOULDER),
new Pair(LEFT_SHOULDER, RIGHT_SHOULDER), new Pair(RIGHT_SHOULDER, RIGHT_ELBOW),
new Pair(RIGHT_ELBOW, RIGHT_WRIST), new Pair(LEFT_SHOULDER, LEFT_HIP),
new Pair(LEFT_HIP, RIGHT_HIP), new Pair(RIGHT_HIP, RIGHT_SHOULDER),
new Pair(LEFT_HIP, LEFT_KNEE), new Pair(LEFT_KNEE, LEFT_ANKLE),
new Pair(RIGHT_HIP, RIGHT_KNEE), new Pair(RIGHT_KNEE, RIGHT_ANKLE));
;
private static final String[] PERMISSIONS = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA};
private static final int REQUEST_PERMISSION = 1;
private static final int REQUEST_PERMISSION_AGAIN = 2;
private boolean isAllGranted;
/**
* Model input shape for images.
*/
private final static int MODEL_WIDTH = 257;
private final static int MODEL_HEIGHT = 257;
private final double minConfidence = 0.5;
private final float circleRadius = 8.0f;
private Paint paint = new Paint();
private final int PREVIEW_WIDTH = 640;
private final int PREVIEW_HEIGHT = 480;
private Posenet posenet;
private int[] rgbBytes = new int[PREVIEW_WIDTH * PREVIEW_HEIGHT];
private byte[][] yuvBytes = new byte[3][];
private SurfaceView surfaceView;
private int lensFacing = CameraCharacteristics.LENS_FACING_BACK;
private PoseNetFragment poseNetFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.posenet_activity_main);
addCameraFragment();
requestPermissions();
}
private void requestPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
isAllGranted = checkPermissionAllGranted(PERMISSIONS);
if (!isAllGranted) {
ActivityCompat.requestPermissions(this, PERMISSIONS, REQUEST_PERMISSION);
} else {
addCameraFragment();
}
} else {
isAllGranted = true;
addCameraFragment();
}
}
private boolean checkPermissionAllGranted(String[] permissions) {
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* Authority application result callback
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (REQUEST_PERMISSION == requestCode) {
isAllGranted = true;
for (int grant : grantResults) {
if (grant != PackageManager.PERMISSION_GRANTED) {
isAllGranted = false;
break;
}
}
if (!isAllGranted) {
openAppDetails();
} else {
addCameraFragment();
}
}
}
private void openAppDetails() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("PoseNet 需要访问 “相机” 和 “外部存储器”,请到 “应用信息 -> 权限” 中授予!");
builder.setPositiveButton("去手动授权", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivityForResult(intent, REQUEST_PERMISSION_AGAIN);
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (REQUEST_PERMISSION_AGAIN == requestCode) {
requestPermissions();
}
}
private void addCameraFragment() {
posenet = new Posenet(this);
poseNetFragment = PoseNetFragment.newInstance();
poseNetFragment.setCameraDataDealListener(this);
// poseNetFragment.setFacingCamera(lensFacing);
getSupportFragmentManager().popBackStack();
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, poseNetFragment)
.commitAllowingStateLoss();
}
@Override
public void dataDeal(Image image, SurfaceView surfaceView) {
if (image == null || image.getPlanes() == null) {
return;
}
this.surfaceView = surfaceView;
fillBytes(image.getPlanes(), yuvBytes);
ImageUtils.convertYUV420ToARGB8888(yuvBytes[0], yuvBytes[1], yuvBytes[2],
PREVIEW_WIDTH, PREVIEW_HEIGHT,
image.getPlanes()[0].getRowStride(),
image.getPlanes()[1].getRowStride(),
image.getPlanes()[1].getPixelStride(),
rgbBytes);
Bitmap imageBitmap = Bitmap.createBitmap(
rgbBytes, PREVIEW_WIDTH, PREVIEW_HEIGHT,
Bitmap.Config.ARGB_8888);
Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(90.0f);
Bitmap rotatedBitmap = Bitmap.createBitmap(
imageBitmap, 0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT,
rotateMatrix, true
);
image.close();
processImage(rotatedBitmap);
public void onClickSwitch(View view) {
poseNetFragment.switchCamera();
}
/**
* Fill the yuvBytes with data from image planes.
*/
private void fillBytes(Image.Plane[] planes, byte[][] yuvBytes) {
// Row stride is the total number of bytes occupied in memory by a row of an image.
// Because of the variable row stride it's not possible to know in
// advance the actual necessary dimensions of the yuv planes
for (int i = 0; i < planes.length; ++i) {
ByteBuffer buffer = planes[i].getBuffer();
if (yuvBytes[i] == null) {
yuvBytes[i] = new byte[buffer.capacity()];
}
buffer.get(yuvBytes[i]);
}
}
/**
* Crop Bitmap to maintain aspect ratio of model input.
*/
private Bitmap cropBitmap(Bitmap bitmap) {
float bitmapRatio = bitmap.getHeight() / bitmap.getWidth();
float modelInputRatio = MODEL_HEIGHT / MODEL_WIDTH;
double maxDifference = 1.0E-5D;
float cropHeight = modelInputRatio - bitmapRatio;
if (Math.abs(cropHeight) < maxDifference) {
return bitmap;
} else {
Bitmap croppedBitmap;
if (modelInputRatio < bitmapRatio) {
cropHeight = (float) bitmap.getHeight() - (float) bitmap.getWidth() / modelInputRatio;
croppedBitmap = Bitmap.createBitmap(bitmap,
0, (int) (cropHeight / 2), bitmap.getWidth(), (int) (bitmap.getHeight() - cropHeight));
} else {
cropHeight = (float) bitmap.getWidth() - (float) bitmap.getHeight() * modelInputRatio;
croppedBitmap = Bitmap.createBitmap(bitmap,
(int) (cropHeight / 2), 0, (int) (bitmap.getWidth() - cropHeight), bitmap.getHeight());
}
return croppedBitmap;
}
}
/**
* Set the paint color and size.
*/
private void setPaint() {
paint.setColor(getResources().getColor(R.color.posenet_text_blue));
paint.setTextSize(80.0f);
paint.setStrokeWidth(8.0f);
}
/**
* Draw bitmap on Canvas.
*/
private void draw(Canvas canvas, Posenet.Person person, Bitmap bitmap) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// Draw `bitmap` and `person` in square canvas.
int screenWidth, screenHeight;
int left, right, top, bottom;
if (canvas.getHeight() > canvas.getWidth()) {
screenWidth = canvas.getWidth();
screenHeight = canvas.getWidth();
left = 0;
top = (canvas.getHeight() - canvas.getWidth()) / 2;
} else {
screenWidth = canvas.getHeight();
screenHeight = canvas.getHeight();
left = (canvas.getWidth() - canvas.getHeight()) / 2;
top = 0;
}
right = left + screenWidth;
bottom = top + screenHeight;
setPaint();
canvas.drawBitmap(
bitmap,
new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()),
new Rect(left, top, right, bottom), paint);
float widthRatio = (float) screenWidth / MODEL_WIDTH;
float heightRatio = (float) screenHeight / MODEL_HEIGHT;
for (Posenet.KeyPoint keyPoint : person.keyPoints) {
if (keyPoint.score > minConfidence) {
Posenet.Position position = keyPoint.position;
float adjustedX = position.x * widthRatio + left;
float adjustedY = position.y * heightRatio + top;
canvas.drawCircle(adjustedX, adjustedY, circleRadius, paint);
}
}
for (int i = 0; i < bodyJoints.size(); i++) {
Pair line = (Pair) bodyJoints.get(i);
Posenet.BodyPart first = (Posenet.BodyPart) line.first;
Posenet.BodyPart second = (Posenet.BodyPart) line.second;
if (person.keyPoints.get(first.ordinal()).score > minConfidence &
person.keyPoints.get(second.ordinal()).score > minConfidence) {
canvas.drawLine(
person.keyPoints.get(first.ordinal()).position.x * widthRatio + left,
person.keyPoints.get(first.ordinal()).position.y * heightRatio + top,
person.keyPoints.get(second.ordinal()).position.x * widthRatio + left,
person.keyPoints.get(second.ordinal()).position.y * heightRatio + top, paint);
}
}
canvas.drawText(String.format("Score: %.2f", person.score),
(15.0f * widthRatio), (30.0f * heightRatio + bottom), paint);
canvas.drawText(String.format("Time: %.2f ms", posenet.lastInferenceTimeNanos * 1.0f / 1_000_000),
(15.0f * widthRatio), (50.0f * heightRatio + bottom), paint
);
// Draw!
surfaceView.getHolder().unlockCanvasAndPost(canvas);
}
/**
* Process image using Posenet library.
*/
private void processImage(Bitmap bitmap) {
// Crop bitmap.
Bitmap croppedBitmap = cropBitmap(bitmap);
// Created scaled version of bitmap for model input.
Bitmap scaledBitmap = Bitmap.createScaledBitmap(croppedBitmap, MODEL_WIDTH, MODEL_HEIGHT, true);
// Perform inference.
Posenet.Person person = posenet.estimateSinglePose(scaledBitmap);
Canvas canvas = surfaceView.getHolder().lockCanvas();
draw(canvas, person, scaledBitmap);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -27,5 +27,14 @@
android:text="MindSpore PoseNet"
android:textColor="#ffffff"
android:textSize="20sp" />
<ImageView
android:onClick="onClickSwitch"
android:clickable="true"
android:layout_marginEnd="10dp"
android:layout_gravity="center_vertical|right"
android:layout_width="45dp"
android:layout_height="45dp"
android:src="@drawable/ic_camera_switch"/>
</androidx.appcompat.widget.Toolbar>
</RelativeLayout>

View File

@ -1,23 +0,0 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mindspore.posenetdemo;
import android.media.Image;
import android.view.SurfaceView;
public interface CameraDataDealListener {
void dataDeal(Image image, SurfaceView surfaceView);
}

View File

@ -19,20 +19,11 @@ import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.hardware.camera2.CameraCharacteristics;
import android.media.Image;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.SurfaceView;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -40,34 +31,8 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.util.Pair;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_ANKLE;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_ELBOW;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_HIP;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_KNEE;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_SHOULDER;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_WRIST;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_ANKLE;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_ELBOW;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_HIP;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_KNEE;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_SHOULDER;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_WRIST;
public class MainActivity extends AppCompatActivity implements CameraDataDealListener {
private final List bodyJoints = Arrays.asList(
new Pair(LEFT_WRIST, LEFT_ELBOW), new Pair(LEFT_ELBOW, LEFT_SHOULDER),
new Pair(LEFT_SHOULDER, RIGHT_SHOULDER), new Pair(RIGHT_SHOULDER, RIGHT_ELBOW),
new Pair(RIGHT_ELBOW, RIGHT_WRIST), new Pair(LEFT_SHOULDER, LEFT_HIP),
new Pair(LEFT_HIP, RIGHT_HIP), new Pair(RIGHT_HIP, RIGHT_SHOULDER),
new Pair(LEFT_HIP, LEFT_KNEE), new Pair(LEFT_KNEE, LEFT_ANKLE),
new Pair(RIGHT_HIP, RIGHT_KNEE), new Pair(RIGHT_KNEE, RIGHT_ANKLE));
public class MainActivity extends AppCompatActivity {
private static final String[] PERMISSIONS = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA};
@ -75,23 +40,6 @@ public class MainActivity extends AppCompatActivity implements CameraDataDealLis
private static final int REQUEST_PERMISSION_AGAIN = 2;
private boolean isAllGranted;
/**
* Model input shape for images.
*/
private final static int MODEL_WIDTH = 257;
private final static int MODEL_HEIGHT = 257;
private final double minConfidence = 0.5;
private final float circleRadius = 8.0f;
private Paint paint = new Paint();
private final int PREVIEW_WIDTH = 640;
private final int PREVIEW_HEIGHT = 480;
private Posenet posenet;
private int[] rgbBytes = new int[PREVIEW_WIDTH * PREVIEW_HEIGHT];
private byte[][] yuvBytes = new byte[3][];
private SurfaceView surfaceView;
private int lensFacing = CameraCharacteristics.LENS_FACING_BACK;
private PoseNetFragment poseNetFragment;
@Override
@ -182,173 +130,16 @@ public class MainActivity extends AppCompatActivity implements CameraDataDealLis
}
private void addCameraFragment() {
posenet = new Posenet(this);
poseNetFragment = PoseNetFragment.newInstance();
poseNetFragment.setCameraDataDealListener(this);
// poseNetFragment.setFacingCamera(lensFacing);
getSupportFragmentManager().popBackStack();
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, poseNetFragment)
.commitAllowingStateLoss();
}
@Override
public void dataDeal(Image image, SurfaceView surfaceView) {
if (image == null || image.getPlanes() == null) {
return;
}
this.surfaceView = surfaceView;
fillBytes(image.getPlanes(), yuvBytes);
ImageUtils.convertYUV420ToARGB8888(yuvBytes[0], yuvBytes[1], yuvBytes[2],
PREVIEW_WIDTH, PREVIEW_HEIGHT,
image.getPlanes()[0].getRowStride(),
image.getPlanes()[1].getRowStride(),
image.getPlanes()[1].getPixelStride(),
rgbBytes);
Bitmap imageBitmap = Bitmap.createBitmap(
rgbBytes, PREVIEW_WIDTH, PREVIEW_HEIGHT,
Bitmap.Config.ARGB_8888);
Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(90.0f);
Bitmap rotatedBitmap = Bitmap.createBitmap(
imageBitmap, 0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT,
rotateMatrix, true
);
image.close();
processImage(rotatedBitmap);
public void onClickSwitch(View view) {
poseNetFragment.switchCamera();
}
/**
* Fill the yuvBytes with data from image planes.
*/
private void fillBytes(Image.Plane[] planes, byte[][] yuvBytes) {
// Row stride is the total number of bytes occupied in memory by a row of an image.
// Because of the variable row stride it's not possible to know in
// advance the actual necessary dimensions of the yuv planes
for (int i = 0; i < planes.length; ++i) {
ByteBuffer buffer = planes[i].getBuffer();
if (yuvBytes[i] == null) {
yuvBytes[i] = new byte[buffer.capacity()];
}
buffer.get(yuvBytes[i]);
}
}
/**
* Crop Bitmap to maintain aspect ratio of model input.
*/
private Bitmap cropBitmap(Bitmap bitmap) {
float bitmapRatio = bitmap.getHeight() / bitmap.getWidth();
float modelInputRatio = MODEL_HEIGHT / MODEL_WIDTH;
double maxDifference = 1.0E-5D;
float cropHeight = modelInputRatio - bitmapRatio;
if (Math.abs(cropHeight) < maxDifference) {
return bitmap;
} else {
Bitmap croppedBitmap;
if (modelInputRatio < bitmapRatio) {
cropHeight = (float) bitmap.getHeight() - (float) bitmap.getWidth() / modelInputRatio;
croppedBitmap = Bitmap.createBitmap(bitmap,
0, (int) (cropHeight / 2), bitmap.getWidth(), (int) (bitmap.getHeight() - cropHeight));
} else {
cropHeight = (float) bitmap.getWidth() - (float) bitmap.getHeight() * modelInputRatio;
croppedBitmap = Bitmap.createBitmap(bitmap,
(int) (cropHeight / 2), 0, (int) (bitmap.getWidth() - cropHeight), bitmap.getHeight());
}
return croppedBitmap;
}
}
/**
* Set the paint color and size.
*/
private void setPaint() {
paint.setColor(getResources().getColor(R.color.text_blue));
paint.setTextSize(80.0f);
paint.setStrokeWidth(8.0f);
}
/**
* Draw bitmap on Canvas.
*/
private void draw(Canvas canvas, Posenet.Person person, Bitmap bitmap) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// Draw `bitmap` and `person` in square canvas.
int screenWidth, screenHeight;
int left, right, top, bottom;
if (canvas.getHeight() > canvas.getWidth()) {
screenWidth = canvas.getWidth();
screenHeight = canvas.getWidth();
left = 0;
top = (canvas.getHeight() - canvas.getWidth()) / 2;
} else {
screenWidth = canvas.getHeight();
screenHeight = canvas.getHeight();
left = (canvas.getWidth() - canvas.getHeight()) / 2;
top = 0;
}
right = left + screenWidth;
bottom = top + screenHeight;
setPaint();
canvas.drawBitmap(
bitmap,
new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()),
new Rect(left, top, right, bottom), paint);
float widthRatio = (float) screenWidth / MODEL_WIDTH;
float heightRatio = (float) screenHeight / MODEL_HEIGHT;
for (Posenet.KeyPoint keyPoint : person.keyPoints) {
if (keyPoint.score > minConfidence) {
Posenet.Position position = keyPoint.position;
float adjustedX = position.x * widthRatio + left;
float adjustedY = position.y * heightRatio + top;
canvas.drawCircle(adjustedX, adjustedY, circleRadius, paint);
}
}
for (int i = 0; i < bodyJoints.size(); i++) {
Pair line = (Pair) bodyJoints.get(i);
Posenet.BodyPart first = (Posenet.BodyPart) line.first;
Posenet.BodyPart second = (Posenet.BodyPart) line.second;
if (person.keyPoints.get(first.ordinal()).score > minConfidence &
person.keyPoints.get(second.ordinal()).score > minConfidence) {
canvas.drawLine(
person.keyPoints.get(first.ordinal()).position.x * widthRatio + left,
person.keyPoints.get(first.ordinal()).position.y * heightRatio + top,
person.keyPoints.get(second.ordinal()).position.x * widthRatio + left,
person.keyPoints.get(second.ordinal()).position.y * heightRatio + top, paint);
}
}
canvas.drawText(String.format("Score: %.2f", person.score),
(15.0f * widthRatio), (30.0f * heightRatio + bottom), paint);
canvas.drawText(String.format("Time: %.2f ms", posenet.lastInferenceTimeNanos * 1.0f / 1_000_000),
(15.0f * widthRatio), (50.0f * heightRatio + bottom), paint
);
// Draw!
surfaceView.getHolder().unlockCanvasAndPost(canvas);
}
/**
* Process image using Posenet library.
*/
private void processImage(Bitmap bitmap) {
// Crop bitmap.
Bitmap croppedBitmap = cropBitmap(bitmap);
// Created scaled version of bitmap for model input.
Bitmap scaledBitmap = Bitmap.createScaledBitmap(croppedBitmap, MODEL_WIDTH, MODEL_HEIGHT, true);
// Perform inference.
Posenet.Person person = posenet.estimateSinglePose(scaledBitmap);
Canvas canvas = surfaceView.getHolder().lockCanvas();
draw(canvas, person, scaledBitmap);
}
}

View File

@ -18,7 +18,14 @@ package com.mindspore.posenetdemo;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
@ -42,29 +49,51 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import androidx.fragment.app.Fragment;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_ANKLE;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_ELBOW;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_HIP;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_KNEE;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_SHOULDER;
import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_WRIST;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_ANKLE;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_ELBOW;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_HIP;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_KNEE;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_SHOULDER;
import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_WRIST;
/**
* A simple {@link Fragment} subclass.
* create an instance of this fragment.
*/
public class PoseNetFragment extends Fragment {
private final List bodyJoints = Arrays.asList(
new Pair(LEFT_WRIST, LEFT_ELBOW), new Pair(LEFT_ELBOW, LEFT_SHOULDER),
new Pair(LEFT_SHOULDER, RIGHT_SHOULDER), new Pair(RIGHT_SHOULDER, RIGHT_ELBOW),
new Pair(RIGHT_ELBOW, RIGHT_WRIST), new Pair(LEFT_SHOULDER, LEFT_HIP),
new Pair(LEFT_HIP, RIGHT_HIP), new Pair(RIGHT_HIP, RIGHT_SHOULDER),
new Pair(LEFT_HIP, LEFT_KNEE), new Pair(LEFT_KNEE, LEFT_ANKLE),
new Pair(RIGHT_HIP, RIGHT_KNEE), new Pair(RIGHT_KNEE, RIGHT_ANKLE));
private static final String TAG = "PoseNetFragment";
private String cameraId = "1";
private int mCameraId = CameraCharacteristics.LENS_FACING_FRONT; // 要打开的摄像头ID
private SurfaceView surfaceView;
private CameraCaptureSession captureSession;
private CameraDevice cameraDevice;
private Size previewSize;
private int previewWidth;
private int previewHeight;
private final int PREVIEW_WIDTH = 640;
private final int PREVIEW_HEIGHT = 480;
private final static int PREVIEW_WIDTH = 640;
private final static int PREVIEW_HEIGHT = 480;
private Size previewSize = new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT);
private HandlerThread backgroundThread;
private Handler backgroundHandler;
private ImageReader imageReader;
@ -73,6 +102,19 @@ public class PoseNetFragment extends Fragment {
private Semaphore cameraOpenCloseLock = new Semaphore(1);//使用信号量 Semaphore 进行多线程任务调度
private boolean flashSupported;
/**
* Model input shape for images.
*/
private final static int MODEL_WIDTH = 257;
private final static int MODEL_HEIGHT = 257;
private final double minConfidence = 0.5;
private final float circleRadius = 8.0f;
private Paint paint = new Paint();
private Posenet posenet;
private int[] rgbBytes = new int[PREVIEW_WIDTH * PREVIEW_HEIGHT];
private byte[][] yuvBytes = new byte[3][];
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
@ -87,12 +129,14 @@ public class PoseNetFragment extends Fragment {
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
cameraOpenCloseLock.release();
cameraDevice.close();
closeCamera();
PoseNetFragment.this.cameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
onDisconnected(cameraDevice);
closeCamera();
Activity activity = getActivity();
if (activity != null) {
activity.finish();
@ -112,12 +156,6 @@ public class PoseNetFragment extends Fragment {
}
};
private CameraDataDealListener cameraDataDealListener;
public void setCameraDataDealListener(CameraDataDealListener cameraDataDealListener) {
this.cameraDataDealListener = cameraDataDealListener;
}
public static PoseNetFragment newInstance() {
PoseNetFragment fragment = new PoseNetFragment();
return fragment;
@ -148,57 +186,24 @@ public class PoseNetFragment extends Fragment {
openCamera();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
posenet = new Posenet(getActivity());
}
public void onPause() {
this.closeCamera();
this.stopBackgroundThread();
super.onPause();
}
public void onDestroy() {
super.onDestroy();
}
/**
* Sets up member variables related to camera.
*/
private void setUpCameraOutputs() {
CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
// We don't use a front facing camera in this sample.
Integer cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING);
if (cameraDirection != null && cameraDirection == CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
previewSize = new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT);
imageReader = ImageReader.newInstance(
PREVIEW_WIDTH, PREVIEW_HEIGHT,
ImageFormat.YUV_420_888, /*maxImages*/ 2
);
previewHeight = previewSize.getHeight();
previewWidth = previewSize.getWidth();
// Initialize the storage bitmaps once when the resolution is known.
// Check if the flash is supported.
flashSupported =
characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) == true;
this.cameraId = cameraId;
// We've found a viable camera and finished setting up member variables,
// so we don't need to iterate through other available cameras.
}
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
public void switchCamera() {
mCameraId ^= 1;
Log.d(TAG, "switchCamera: mCameraId: " + mCameraId);
closeCamera();
openCamera();
}
/**
@ -206,14 +211,23 @@ public class PoseNetFragment extends Fragment {
*/
@SuppressLint("MissingPermission")
private void openCamera() {
setUpCameraOutputs();
CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(Integer.toString(mCameraId));
previewSize = new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT);
imageReader = ImageReader.newInstance(
PREVIEW_WIDTH, PREVIEW_HEIGHT,
ImageFormat.YUV_420_888, /*maxImages*/ 2
);
imageReader.setOnImageAvailableListener(imageAvailableListener, backgroundHandler);
// Check if the flash is supported.
flashSupported =
characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) == true;
// Wait for camera to open - 2.5 seconds is sufficient
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
manager.openCamera(cameraId, mStateCallback, backgroundHandler);
manager.openCamera(Integer.toString(mCameraId), mStateCallback, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
@ -266,31 +280,48 @@ public class PoseNetFragment extends Fragment {
}
}
private final ImageReader.OnImageAvailableListener imageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
if (previewWidth != 0 && previewHeight != 0 && imageReader != null) {
if (imageReader != null) {
Image image = imageReader.acquireLatestImage();
if (cameraDataDealListener != null) {
cameraDataDealListener.dataDeal(image, surfaceView);
if (image == null || image.getPlanes() == null) {
return;
}
fillBytes(image.getPlanes(), yuvBytes);
ImageUtils.convertYUV420ToARGB8888(yuvBytes[0], yuvBytes[1], yuvBytes[2],
PREVIEW_WIDTH, PREVIEW_HEIGHT,
image.getPlanes()[0].getRowStride(),
image.getPlanes()[1].getRowStride(),
image.getPlanes()[1].getPixelStride(),
rgbBytes);
Bitmap imageBitmap = Bitmap.createBitmap(
rgbBytes, PREVIEW_WIDTH, PREVIEW_HEIGHT,
Bitmap.Config.ARGB_8888);
Matrix rotateMatrix = new Matrix();
if (mCameraId == CameraCharacteristics.LENS_FACING_FRONT) {
rotateMatrix.postRotate(90.0f);
} else if (mCameraId == CameraCharacteristics.LENS_FACING_BACK) {
rotateMatrix.postRotate(270.0f);
rotateMatrix.postScale(-1.0f, 1.0f);
}
Bitmap rotatedBitmap = Bitmap.createBitmap(
imageBitmap, 0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT,
rotateMatrix, true
);
processImage(rotatedBitmap);
image.close();
}
}
};
/**
* Creates a new [CameraCaptureSession] for camera preview.
*/
private void createCameraPreviewSession() {
try {
// We capture images from preview in YUV format.
imageReader = ImageReader.newInstance(
previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2);
imageReader.setOnImageAvailableListener(imageAvailableListener, backgroundHandler);
// This is the surface we need to record images for processing.
Surface recordingSurface = imageReader.getSurface();
@ -348,4 +379,136 @@ public class PoseNetFragment extends Fragment {
}
}
/**
* Fill the yuvBytes with data from image planes.
*/
private void fillBytes(Image.Plane[] planes, byte[][] yuvBytes) {
// Row stride is the total number of bytes occupied in memory by a row of an image.
// Because of the variable row stride it's not possible to know in
// advance the actual necessary dimensions of the yuv planes
for (int i = 0; i < planes.length; ++i) {
ByteBuffer buffer = planes[i].getBuffer();
if (yuvBytes[i] == null) {
yuvBytes[i] = new byte[buffer.capacity()];
}
buffer.get(yuvBytes[i]);
}
}
/**
* Crop Bitmap to maintain aspect ratio of model input.
*/
private Bitmap cropBitmap(Bitmap bitmap) {
float bitmapRatio = bitmap.getHeight() / bitmap.getWidth();
float modelInputRatio = MODEL_HEIGHT / MODEL_WIDTH;
double maxDifference = 1.0E-5D;
float cropHeight = modelInputRatio - bitmapRatio;
if (Math.abs(cropHeight) < maxDifference) {
return bitmap;
} else {
Bitmap croppedBitmap;
if (modelInputRatio < bitmapRatio) {
cropHeight = (float) bitmap.getHeight() - (float) bitmap.getWidth() / modelInputRatio;
croppedBitmap = Bitmap.createBitmap(bitmap,
0, (int) (cropHeight / 2), bitmap.getWidth(), (int) (bitmap.getHeight() - cropHeight));
} else {
cropHeight = (float) bitmap.getWidth() - (float) bitmap.getHeight() * modelInputRatio;
croppedBitmap = Bitmap.createBitmap(bitmap,
(int) (cropHeight / 2), 0, (int) (bitmap.getWidth() - cropHeight), bitmap.getHeight());
}
return croppedBitmap;
}
}
/**
* Set the paint color and size.
*/
private void setPaint() {
paint.setColor(getResources().getColor(R.color.text_blue));
paint.setTextSize(80.0f);
paint.setStrokeWidth(8.0f);
}
/**
* Draw bitmap on Canvas.
*/
private void draw(Canvas canvas, Posenet.Person person, Bitmap bitmap) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// Draw `bitmap` and `person` in square canvas.
int screenWidth, screenHeight;
int left, right, top, bottom;
if (canvas.getHeight() > canvas.getWidth()) {
screenWidth = canvas.getWidth();
screenHeight = canvas.getWidth();
left = 0;
top = (canvas.getHeight() - canvas.getWidth()) / 2;
} else {
screenWidth = canvas.getHeight();
screenHeight = canvas.getHeight();
left = (canvas.getWidth() - canvas.getHeight()) / 2;
top = 0;
}
right = left + screenWidth;
bottom = top + screenHeight;
setPaint();
canvas.drawBitmap(
bitmap,
new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()),
new Rect(left, top, right, bottom), paint);
float widthRatio = (float) screenWidth / MODEL_WIDTH;
float heightRatio = (float) screenHeight / MODEL_HEIGHT;
for (Posenet.KeyPoint keyPoint : person.keyPoints) {
if (keyPoint.score > minConfidence) {
Posenet.Position position = keyPoint.position;
float adjustedX = position.x * widthRatio + left;
float adjustedY = position.y * heightRatio + top;
canvas.drawCircle(adjustedX, adjustedY, circleRadius, paint);
}
}
for (int i = 0; i < bodyJoints.size(); i++) {
Pair line = (Pair) bodyJoints.get(i);
Posenet.BodyPart first = (Posenet.BodyPart) line.first;
Posenet.BodyPart second = (Posenet.BodyPart) line.second;
if (person.keyPoints.get(first.ordinal()).score > minConfidence &
person.keyPoints.get(second.ordinal()).score > minConfidence) {
canvas.drawLine(
person.keyPoints.get(first.ordinal()).position.x * widthRatio + left,
person.keyPoints.get(first.ordinal()).position.y * heightRatio + top,
person.keyPoints.get(second.ordinal()).position.x * widthRatio + left,
person.keyPoints.get(second.ordinal()).position.y * heightRatio + top, paint);
}
}
canvas.drawText(String.format("Score: %.2f", person.score),
(15.0f * widthRatio), (30.0f * heightRatio + bottom), paint);
canvas.drawText(String.format("Time: %.2f ms", posenet.lastInferenceTimeNanos * 1.0f / 1_000_000),
(15.0f * widthRatio), (50.0f * heightRatio + bottom), paint
);
// Draw!
surfaceView.getHolder().unlockCanvasAndPost(canvas);
}
/**
* Process image using Posenet library.
*/
private void processImage(Bitmap bitmap) {
// Crop bitmap.
Bitmap croppedBitmap = cropBitmap(bitmap);
// Created scaled version of bitmap for model input.
Bitmap scaledBitmap = Bitmap.createScaledBitmap(croppedBitmap, MODEL_WIDTH, MODEL_HEIGHT, true);
// Perform inference.
Posenet.Person person = posenet.estimateSinglePose(scaledBitmap);
Canvas canvas = surfaceView.getHolder().lockCanvas();
draw(canvas, person, scaledBitmap);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -19,7 +19,7 @@
android:background="#66000000">
<TextView
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@drawable/logo2"
android:drawablePadding="5dp"
@ -27,5 +27,14 @@
android:text="MindSpore PoseNet"
android:textColor="#ffffff"
android:textSize="20sp" />
<ImageView
android:onClick="onClickSwitch"
android:clickable="true"
android:layout_marginEnd="10dp"
android:layout_gravity="center_vertical|right"
android:layout_width="45dp"
android:layout_height="45dp"
android:src="@drawable/ic_camera_switch"/>
</androidx.appcompat.widget.Toolbar>
</RelativeLayout>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.mindspore.styletransferdemo">
<uses-permission android:name="android.permission.CAMERA" />
@ -34,6 +35,18 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.mindspore.styletransferdemo.fileprovider"
android:exported="false"
tools:replace="android:authorities"
android:grantUriPermissions="true">
<meta-data
tools:replace="android:resource"
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/style_file_paths" />
</provider>
</application>
</manifest>

View File

@ -89,7 +89,7 @@ public class BitmapUtils {
}
// Scale pictures to screen width.
private static Bitmap zoomImage(Bitmap imageBitmap, int targetWidth, int maxHeight) {
public static Bitmap zoomImage(Bitmap imageBitmap, int targetWidth, int maxHeight) {
float scaleFactor =
Math.max(
(float) imageBitmap.getWidth() / (float) targetWidth,
@ -104,6 +104,26 @@ public class BitmapUtils {
return resizedBitmap;
}
public static Bitmap changeBitmapSize(Bitmap bitmap, int targetWidth, int targetHeight) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Log.e("width", "width:" + width);
Log.e("height", "height:" + height);
float scaleWidth = ((float) targetWidth) / width;
float scaleHeight = ((float) targetHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
bitmap.getWidth();
bitmap.getHeight();
Log.e("newWidth", "newWidth" + bitmap.getWidth());
Log.e("newHeight", "newHeight" + bitmap.getHeight());
return bitmap;
}
/**
* Get the rotation angle of the photo.
*

View File

@ -16,16 +16,24 @@
package com.mindspore.styletransferdemo;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.exifinterface.media.ExifInterface;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
@ -33,6 +41,8 @@ import java.nio.ByteOrder;
public class ImageUtils {
private static final String TAG = "ImageUtils";
private static Matrix decodeExifOrientation(int orientation) {
Matrix matrix = new Matrix();
@ -198,4 +208,59 @@ public class ImageUtils {
}
return ret;
}
// Save the picture to the system album and refresh it.
public static void saveToAlbum(final Context context, Bitmap bitmap) {
File file = null;
String fileName = System.currentTimeMillis() + ".jpg";
File root = new File(Environment.getExternalStorageDirectory().getAbsoluteFile(), context.getPackageName());
File dir = new File(root, "image");
if (dir.mkdirs() || dir.isDirectory()) {
file = new File(dir, fileName);
}
FileOutputStream os = null;
try {
os = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
os.flush();
} catch (FileNotFoundException e) {
Log.e(TAG, e.getMessage());
} catch (IOException e) {
Log.e(TAG, e.getMessage());
} finally {
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
if (file == null) {
return;
}
// Gallery refresh.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
String path = null;
try {
path = file.getCanonicalPath();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
MediaScannerConnection.scanFile(context, new String[]{path}, null,
new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(uri);
context.sendBroadcast(mediaScanIntent);
}
});
} else {
String relationDir = file.getParent();
File file1 = new File(relationDir);
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(file1.getAbsoluteFile())));
}
}
}

View File

@ -16,50 +16,74 @@
package com.mindspore.styletransferdemo;
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.provider.Settings;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
public class MainActivity extends AppCompatActivity implements View.OnClickListener, StyleFragment.OnListFragmentInteractionListener {
import java.io.File;
import java.io.FileNotFoundException;
public class MainActivity extends AppCompatActivity implements OnBackgroundImageListener {
private static final String TAG = "MainActivity";
private static final int[] IMAGES = {R.drawable.style0, R.drawable.style1, R.drawable.style2, R.drawable.style3, R.drawable.style4,
R.drawable.style5, R.drawable.style6, R.drawable.style7, R.drawable.style8, R.drawable.style9,
R.drawable.style10, R.drawable.style11, R.drawable.style12, R.drawable.style13, R.drawable.style14,
R.drawable.style15, R.drawable.style16, R.drawable.style17, R.drawable.style18, R.drawable.style19, R.drawable.add};
private static final String[] PERMISSIONS = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA};
private static final int REQUEST_PERMISSION = 1;
private static final int RC_CHOOSE_PHOTO = 2;
private static final int RC_CHOOSE_PHOTO_FOR_BACKGROUND = 3;
private static final int RC_CHOOSE_CAMERA = 4;
private boolean isAllGranted;
private StyleTransferModelExecutor transferModelExecutor;
private boolean isHasPermssion;
private boolean isRunningModel;
private ImageView imgOrigin, imgStyle, imgResult;
private ProgressBar progressResult;
private ImageView imgPreview;
private Uri imageUri;
private TextView textOriginImage;
private ProgressBar progressBar;
private RecyclerView recyclerView;
private Integer maxWidthOfImage;
private Integer maxHeightOfImage;
private boolean isLandScape;
private Bitmap originBitmap, styleBitmap;
private StyleFragment styleFragment;
private String selectedStyle;
private Bitmap originBitmap, styleBitmap, resultBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -71,23 +95,35 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
}
private void init() {
imgOrigin = findViewById(R.id.img_origin);
imgStyle = findViewById(R.id.img_style);
imgResult = findViewById(R.id.img_result);
progressResult = findViewById(R.id.progress_circular);
imgPreview = findViewById(R.id.img_origin);
textOriginImage = findViewById(R.id.tv_image);
progressBar = findViewById(R.id.progress);
recyclerView = findViewById(R.id.recyclerview);
imgOrigin.setOnClickListener(this);
imgStyle.setOnClickListener(this);
imgResult.setOnClickListener(this);
styleFragment = StyleFragment.newInstance();
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
recyclerView.setAdapter(new StyleRecyclerViewAdapter(this, IMAGES, this));
transferModelExecutor = new StyleTransferModelExecutor(this, false);
}
private void requestPermissions() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA}, REQUEST_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
isAllGranted = checkPermissionAllGranted(PERMISSIONS);
if (!isAllGranted) {
ActivityCompat.requestPermissions(this, PERMISSIONS, REQUEST_PERMISSION);
}
} else {
isAllGranted = true;
}
}
private boolean checkPermissionAllGranted(String[] permissions) {
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
@ -96,43 +132,115 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (REQUEST_PERMISSION == requestCode) {
isHasPermssion = true;
}
}
isAllGranted = true;
@Override
public void onClick(View view) {
if (view.getId() == R.id.img_origin) {
if (isHasPermssion) {
openGallay();
} else {
requestPermissions();
for (int grant : grantResults) {
if (grant != PackageManager.PERMISSION_GRANTED) {
isAllGranted = false;
break;
}
}
} else if (view.getId() == R.id.img_style) {
if (!isRunningModel) {
styleFragment.show(getSupportFragmentManager(), TAG);
if (!isAllGranted) {
openAppDetails();
}
}
}
private void openGallay() {
private void openAppDetails() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("HiMindSpore需要访问 “相机” 和 “外部存储器”,请到 “应用信息 -> 权限” 中授予!");
builder.setPositiveButton("去手动授权", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);
}
});
builder.setNegativeButton("取消", null);
builder.show();
}
public void onClickPhoto(View view) {
if (isAllGranted) {
openGallay(RC_CHOOSE_PHOTO);
textOriginImage.setVisibility(View.GONE);
} else {
requestPermissions();
}
}
public void onClickCamera(View view) {
if (isAllGranted) {
openCamera();
textOriginImage.setVisibility(View.GONE);
} else {
requestPermissions();
}
}
public void onClickRecovery(View view) {
if (originBitmap != null) {
Glide.with(this).load(originBitmap).into(imgPreview);
} else {
Toast.makeText(this, "Please select an original picture first", Toast.LENGTH_SHORT).show();
}
}
public void onClickSave(View view) {
if (this.resultBitmap == null) {
Log.e(TAG, "null processed image");
Toast.makeText(this.getApplicationContext(), R.string.no_pic_neededSave, Toast.LENGTH_SHORT).show();
} else {
ImageUtils.saveToAlbum(getApplicationContext(), this.resultBitmap);
Toast.makeText(this.getApplicationContext(), R.string.save_success, Toast.LENGTH_SHORT).show();
}
}
private void openGallay(int request) {
Intent intentToPickPic = new Intent(Intent.ACTION_PICK, null);
intentToPickPic.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(intentToPickPic, RC_CHOOSE_PHOTO);
startActivityForResult(intentToPickPic, request);
}
private void openCamera() {
if (isAllGranted) {
Intent intentToTakePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String mTempPhotoPath = Environment.getExternalStorageDirectory() + File.separator + "photo.jpeg";
imageUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".fileprovider", new File(mTempPhotoPath));
intentToTakePhoto.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intentToTakePhoto, RC_CHOOSE_CAMERA);
} else {
requestPermissions();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (RC_CHOOSE_PHOTO == requestCode && null != data && null != data.getData()) {
if (data != null) {
this.imageUri = data.getData();
showOriginImage();
if (resultCode == RESULT_OK) {
if (RC_CHOOSE_PHOTO == requestCode) {
if (null != data && null != data.getData()) {
this.imageUri = data.getData();
showOriginImage();
} else {
finish();
}
} else if (RC_CHOOSE_PHOTO_FOR_BACKGROUND == requestCode) {
if (null != data && null != data.getData()) {
showCustomBack(data.getData());
} else {
finish();
}
} else if (RC_CHOOSE_CAMERA == requestCode) {
showOriginCamera();
}
} else {
finish();
}
}
@ -140,56 +248,81 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
Pair<Integer, Integer> targetedSize = this.getTargetSize();
int targetWidth = targetedSize.first;
int maxHeight = targetedSize.second;
originBitmap = BitmapUtils.loadFromPath(MainActivity.this, imageUri, targetWidth, maxHeight);
originBitmap = BitmapUtils.loadFromPath(this, imageUri, targetWidth, maxHeight);
// Determine how much to scale down the image.
Log.i(TAG, "resized image size width:" + originBitmap.getWidth() + ",height: " + originBitmap.getHeight());
Log.e(TAG, "resized image size width:" + originBitmap.getWidth() + ",height: " + originBitmap.getHeight());
if (originBitmap != null) {
Glide.with(this).load(originBitmap).into(imgOrigin);
Glide.with(this).load(originBitmap).into(imgPreview);
}
}
@Override
public void onListFragmentInteraction(String item) {
this.selectedStyle = item;
styleFragment.dismiss();
startRunningModel();
private void showOriginCamera() {
try {
Pair<Integer, Integer> targetedSize = this.getTargetSize();
int targetWidth = targetedSize.first;
int maxHeight = targetedSize.second;
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
originBitmap = BitmapUtils.zoomImage(bitmap, targetWidth, maxHeight);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// Determine how much to scale down the image.
Log.e(TAG, "resized image size width:" + originBitmap.getWidth() + ",height: " + originBitmap.getHeight());
if (originBitmap != null) {
Glide.with(this).load(originBitmap).into(imgPreview);
}
}
private void startRunningModel() {
if (!isRunningModel && !TextUtils.isEmpty(selectedStyle)) {
styleBitmap = ImageUtils.loadBitmapFromResources(this, getUriFromAssetThumb(selectedStyle));
Glide.with(this)
.load(styleBitmap)
.into(imgStyle);
private void showCustomBack(Uri imageUri) {
Pair<Integer, Integer> targetedSize = this.getTargetSize();
int targetWidth = targetedSize.first;
int maxHeight = targetedSize.second;
styleBitmap = BitmapUtils.loadFromPath(this, imageUri, targetWidth, maxHeight);
startRunningModel(styleBitmap);
}
if (originBitmap == null) {
Toast.makeText(this, "Please select an original picture first", Toast.LENGTH_SHORT).show();
return;
}
progressResult.setVisibility(View.VISIBLE);
@Override
public void onBackImageSelected(int position) {
styleBitmap = BitmapFactory.decodeResource(getResources(), IMAGES[position]);
startRunningModel(styleBitmap);
}
@Override
public void onImageAdd(View view) {
openGallay(RC_CHOOSE_PHOTO_FOR_BACKGROUND);
}
private void startRunningModel(Bitmap styleBitmap) {
if (originBitmap == null) {
Toast.makeText(this, "Please select an original picture first", Toast.LENGTH_SHORT).show();
return;
}
if (!isRunningModel) {
isRunningModel = true;
progressBar.setVisibility(View.VISIBLE);
ModelExecutionResult result = transferModelExecutor.execute(originBitmap, styleBitmap);
Glide.with(this).load(result.getStyledImage()).into(imgResult);
progressResult.setVisibility(View.GONE);
if (null != result && null != result.getStyledImage()) {
resultBitmap = BitmapUtils.changeBitmapSize(result.getStyledImage(), originBitmap.getWidth(), originBitmap.getHeight());
Log.e("AAA", "w>>" + resultBitmap.getWidth() + ">>>h>>" + resultBitmap.getHeight());
Glide.with(this).load(resultBitmap).override(resultBitmap.getWidth(), resultBitmap.getHeight()).into(imgPreview);
} else {
Toast.makeText(this, "ModelExecute failed", Toast.LENGTH_SHORT).show();
}
isRunningModel = false;
progressBar.setVisibility(View.INVISIBLE);
} else {
Toast.makeText(this, "Previous Model still running", Toast.LENGTH_SHORT).show();
}
}
private String getUriFromAssetThumb(String thumb) {
return "thumbnails/" + thumb;
}
// Returns max width of image.
private Integer getMaxWidthOfImage() {
if (this.maxWidthOfImage == null) {
if (this.isLandScape) {
this.maxWidthOfImage = ((View) this.imgOrigin.getParent()).getHeight();
this.maxWidthOfImage = ((View) this.imgPreview.getParent()).getHeight();
} else {
this.maxWidthOfImage = ((View) this.imgOrigin.getParent()).getWidth();
this.maxWidthOfImage = ((View) this.imgPreview.getParent()).getWidth();
}
}
return this.maxWidthOfImage;
@ -199,9 +332,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
private Integer getMaxHeightOfImage() {
if (this.maxHeightOfImage == null) {
if (this.isLandScape) {
this.maxHeightOfImage = ((View) this.imgOrigin.getParent()).getWidth();
this.maxHeightOfImage = ((View) this.imgPreview.getParent()).getWidth();
} else {
this.maxHeightOfImage = ((View) this.imgOrigin.getParent()).getHeight();
this.maxHeightOfImage = ((View) this.imgPreview.getParent()).getHeight();
}
}
return this.maxHeightOfImage;
@ -219,5 +352,4 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
return new Pair<>(targetWidth, targetHeight);
}
}

View File

@ -0,0 +1,9 @@
package com.mindspore.styletransferdemo;
import android.view.View;
public interface OnBackgroundImageListener {
void onBackImageSelected(int position);
void onImageAdd(View view);
}

View File

@ -1,92 +0,0 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mindspore.styletransferdemo;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A simple {@link Fragment} subclass.
* Use the {@link StyleFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class StyleFragment extends DialogFragment {
private OnListFragmentInteractionListener listener;
public StyleFragment() {
// Required empty public constructor
}
public static StyleFragment newInstance() {
StyleFragment fragment = new StyleFragment();
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_style, container, false);
List<String> styles = new ArrayList<>();
try {
styles.addAll(Arrays.asList(getActivity().getAssets().list("thumbnails")));
} catch (IOException e) {
e.printStackTrace();
}
if (view instanceof RecyclerView) {
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 3);
((RecyclerView) view).setLayoutManager(gridLayoutManager);
((RecyclerView) view).setAdapter(new StyleRecyclerViewAdapter(getActivity(), styles, listener));
}
return view;
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof OnListFragmentInteractionListener) {
this.listener = (StyleFragment.OnListFragmentInteractionListener) context;
}
}
public void onDetach() {
super.onDetach();
this.listener = null;
}
public interface OnListFragmentInteractionListener {
void onListFragmentInteraction(String item);
}
}

View File

@ -16,7 +16,6 @@
package com.mindspore.styletransferdemo;
import android.content.Context;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -27,35 +26,16 @@ import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.List;
public class StyleRecyclerViewAdapter extends RecyclerView.Adapter<StyleRecyclerViewAdapter.StyleItemViewHolder> {
private View.OnClickListener mOnClickListener;
private List<String> stylesList;
private Context context;
private StyleFragment.OnListFragmentInteractionListener mListener;
private final int[] IMAGES;
private final Context context;
private final OnBackgroundImageListener mListener;
public StyleRecyclerViewAdapter(Context context, List<String> stylesList, StyleFragment.OnListFragmentInteractionListener mListener) {
this.stylesList = stylesList;
public StyleRecyclerViewAdapter(Context context, int[] IMAGES, OnBackgroundImageListener mListener) {
this.IMAGES = IMAGES;
this.context = context;
this.mListener = mListener;
this.mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
}
};
this.mOnClickListener = (View.OnClickListener) (new View.OnClickListener() {
public final void onClick(View v) {
if (v.getTag() != null && v.getTag() instanceof String) {
mListener.onListFragmentInteraction(String.valueOf(v.getTag()));
}
}
});
}
@NonNull
@ -68,21 +48,27 @@ public class StyleRecyclerViewAdapter extends RecyclerView.Adapter<StyleRecycler
@Override
public void onBindViewHolder(@NonNull StyleItemViewHolder holder, int position) {
String imagePath = stylesList.get(position);
Glide.with(context).
load(Uri.parse("file:///android_asset/thumbnails/" + imagePath)).
centerInside().
load(IMAGES[position]).
into(holder.getImageView());
View view = holder.getMView();
view.setTag(imagePath);
view.setOnClickListener(this.mOnClickListener);
view.setTag(IMAGES[position]);
view.setOnClickListener(view1 -> {
if (mListener != null) {
if (IMAGES.length - 1 == position) {
mListener.onImageAdd(holder.getImageView());
} else {
mListener.onBackImageSelected(position);
}
}
});
}
@Override
public int getItemCount() {
return stylesList == null ? 0 : stylesList.size();
return IMAGES == null ? 0 : IMAGES.length;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360">
<shape
android:innerRadiusRatio="3"
android:shape="ring"
android:thicknessRatio="8"
android:useLevel="false">
<gradient
android:centerColor="#62AEEC"
android:centerY="0.50"
android:endColor="#1063A5"
android:startColor="#61C2EC"
android:type="sweep"
android:useLevel="false" />
</shape>
</animated-rotate>

View File

@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical"
tools:context=".TestActivity">
android:background="@color/colorPrimary"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
@ -20,57 +18,125 @@
android:drawableStart="@drawable/logo2"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:maxLines="1"
android:text="MindSpore StyleTransfer"
android:textColor="#ffffff"
android:textSize="20sp" />
</androidx.appcompat.widget.Toolbar>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/img_origin"
android:layout_width="256dp"
android:layout_height="256dp"
android:layout_margin="10dp"
android:scaleType="fitXY"
android:src="@android:drawable/ic_menu_gallery" />
<ImageView
android:id="@+id/img_style"
android:layout_width="256dp"
android:layout_height="256dp"
android:layout_margin="10dp"
android:scaleType="fitXY"
android:src="@drawable/style_chose" />
</LinearLayout>
</HorizontalScrollView>
<FrameLayout
android:layout_width="256dp"
android:layout_height="256dp"
android:layout_gravity="center"
android:layout_margin="20dp">
<ProgressBar
android:visibility="invisible"
android:id="@+id/progress_circular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
android:layout_width="match_parent"
android:layout_height="300dp">
<ImageView
android:id="@+id/img_result"
android:layout_width="256dp"
android:layout_height="256dp"
android:padding="4dp"
android:src="@android:drawable/ic_menu_report_image" />
android:id="@+id/img_origin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:scaleType="fitXY" />
<TextView
android:id="@+id/tv_image"
android:layout_width="206dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:gravity="center"
android:paddingLeft="4dp"
android:text="Choose a Image"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="20sp" />
<ProgressBar
android:id="@+id/progress"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/progressbar"
android:visibility="invisible" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:background="@color/gray_btn"
android:gravity="center"
android:onClick="onClickPhoto"
android:text="PHOTO"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="12sp" />
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:background="@color/gray_btn"
android:gravity="center"
android:onClick="onClickCamera"
android:text="CAMERA"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="12sp" />
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:background="@color/gray_btn"
android:gravity="center"
android:onClick="onClickRecovery"
android:text="RECOVERY"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="12sp" />
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="20dp"
android:layout_weight="1"
android:background="@color/gray_btn"
android:gravity="center"
android:onClick="onClickSave"
android:text="SAVE"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:text="Choose a Style"
android:textColor="@color/white"
android:textSize="20sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:fadeScrollbars="false"
android:scrollbarSize="6dp"
android:scrollbarStyle="outsideInset"
android:scrollbarThumbVertical="@color/gray"
android:scrollbars="vertical" />
</LinearLayout>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimary">#303030</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
@ -13,4 +13,5 @@
<color name="text_yellow">#F8E71C</color>
<color name="text_orange">#FF844D</color>
<color name="text_green">#66B50A</color>
</resources>

View File

@ -2,4 +2,6 @@
<string name="app_name">StyleTransfer</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="no_pic_neededSave">Null Image needed to save</string>
<string name="save_success">Save success</string>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_files"
path="." />
</paths>