specification has submitted code.

This commit is contained in:
WinterGeng
2022-11-07 18:50:53 +08:00
parent 856b623cad
commit 87823173bb
26 changed files with 23 additions and 1552 deletions

View File

@@ -31,9 +31,9 @@ import android.widget.TextView;
import com.baidu.paddle.fastdeploy.RuntimeOption;
import com.baidu.paddle.fastdeploy.app.examples.R;
import com.baidu.paddle.fastdeploy.app.ui.CameraSurfaceView;
import com.baidu.paddle.fastdeploy.app.ui.view.CameraSurfaceView;
import com.baidu.paddle.fastdeploy.app.ui.view.ResultListView;
import com.baidu.paddle.fastdeploy.app.ui.view.Utils;
import com.baidu.paddle.fastdeploy.app.ui.Utils;
import com.baidu.paddle.fastdeploy.app.ui.view.adapter.DetectResultAdapter;
import com.baidu.paddle.fastdeploy.app.ui.view.model.BaseResultModel;
import com.baidu.paddle.fastdeploy.vision.DetectionResult;
@@ -90,7 +90,7 @@ public class MainActivity extends Activity implements View.OnClickListener, Came
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
setContentView(R.layout.default_activity_main);
// Clear all setting items to avoid app crashing due to the incorrect settings
initSettings();
@@ -325,7 +325,7 @@ public class MainActivity extends Activity implements View.OnClickListener, Came
results.add(new BaseResultModel(1, "cup", 0.4f));
results.add(new BaseResultModel(2, "pen", 0.6f));
results.add(new BaseResultModel(3, "tang", 1.0f));
final DetectResultAdapter adapter = new DetectResultAdapter(this, R.layout.result_detect_item, results);
final DetectResultAdapter adapter = new DetectResultAdapter(this, R.layout.default_result_page_item, results);
detectResultView.setAdapter(adapter);
detectResultView.invalidate();

View File

@@ -10,8 +10,8 @@ import android.preference.PreferenceManager;
import android.support.v7.app.ActionBar;
import com.baidu.paddle.fastdeploy.app.examples.R;
import com.baidu.paddle.fastdeploy.app.ui.AppCompatPreferenceActivity;
import com.baidu.paddle.fastdeploy.app.ui.view.Utils;
import com.baidu.paddle.fastdeploy.app.ui.view.AppCompatPreferenceActivity;
import com.baidu.paddle.fastdeploy.app.ui.Utils;
import java.util.ArrayList;
import java.util.List;
@@ -46,7 +46,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity implements
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
addPreferencesFromResource(R.xml.detection_settings);
ActionBar supportActionBar = getSupportActionBar();
if (supportActionBar != null) {
supportActionBar.setDisplayHomeAsUpEnabled(true);

View File

@@ -1,4 +1,4 @@
package com.baidu.paddle.fastdeploy.app.ui.view;
package com.baidu.paddle.fastdeploy.app.ui;
import android.content.Context;
import android.content.res.Resources;

View File

@@ -1,19 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.camera;
import android.graphics.Bitmap;
/**
* Created by ruanshimin on 2017/11/30.
*/
public class CameraListener {
public interface CommonListener {
void onSurfaceReady();
void onSwitchCamera();
}
public interface TakePictureListener {
void onTakenPicture(Bitmap bitmap);
}
}

View File

@@ -1,296 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.camera;
import static android.hardware.Camera.getCameraInfo;
import static android.hardware.Camera.getNumberOfCameras;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.util.Log;
import com.baidu.paddle.fastdeploy.app.ui.util.ImageUtil;
import com.baidu.paddle.fastdeploy.app.ui.util.UiLog;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Created by ruanshimin on 2018/4/16.
*/
public class CameraProxy1 implements ICameraProxy {
private static final int STATUS_INIT = 0;
private static final int STATUS_OPENED = 1;
private static final int STATUS_PREVIEWING = 2;
private static final int TEXTURE_STATUS_INITED = 0;
private static final int TEXTURE_STATUS_READY = 1;
private SurfaceTexture mSurfaceTexture;
private boolean isBack = true;
private Camera mCamera;
private int status;
private int textureStatus;
private boolean hasDestoryUnexcepted = false;
private int layoutWidth;
private int layoutHeight;
private int[] previewSize = new int[2];
private CameraListener.CommonListener mCameraListener;
private int minPreviewCandidateWidth = 0;
private int previewRotation = 90;
private int displayRotation = 0;
private int previewCaptureRotation = 0;
private Camera.Parameters cameraParameters;
public CameraProxy1(int width, int height) {
layoutWidth = width;
layoutHeight = height;
status = STATUS_INIT;
textureStatus = TEXTURE_STATUS_INITED;
}
public int[] getPreviewSize() {
return previewSize;
}
private Camera.Size getPreviewSize(List<Camera.Size> list) {
ArrayList validSizeList = new ArrayList<Camera.Size>();
float ratio = (float) layoutHeight / layoutWidth;
for (Camera.Size size : list) {
if ((float) size.width / size.height >= ratio && size.width > minPreviewCandidateWidth) {
validSizeList.add(size);
}
}
// 没有符合条件的,直接返回第一个吧
if (validSizeList.size() == 0) {
UiLog.info("no valid preview size");
return list.get(0);
}
Camera.Size size = (Camera.Size) Collections.min(validSizeList, new Comparator<Camera.Size>() {
@Override
public int compare(Camera.Size s1, Camera.Size s2) {
return s1.width - s2.width;
}
});
return (Camera.Size) validSizeList.get(1);
// return size;
}
public Camera open(boolean isOpenBack) {
int numberOfCameras = getNumberOfCameras();
UiLog.info("cameraNumber is " + numberOfCameras);
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
getCameraInfo(i, cameraInfo);
if (isOpenBack) {
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
caculatePreviewRotation(cameraInfo);
return Camera.open(i);
}
} else {
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
caculatePreviewRotation(cameraInfo);
return Camera.open(i);
}
}
}
// 兼容只有前置摄像头的开发板
return Camera.open(0);
}
public void setDisplayRotation(int degree) {
displayRotation = degree;
}
private void caculatePreviewRotation(Camera.CameraInfo info) {
int degree;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
degree = (info.orientation + displayRotation) % 360;
degree = (360 - degree) % 360; // compensate the mirror
previewCaptureRotation = (360 - degree) % 360;
} else { // back-facing
degree = (info.orientation - displayRotation + 360) % 360;
previewCaptureRotation = (360 + degree) % 360;
}
previewRotation = degree;
}
@Override
public void startPreview() {
// MIUI上会在activity stop时destory关闭相机触发textureview的destory方法
if (hasDestoryUnexcepted) {
openCamera();
}
// 如果已经TextureAvailable设置texture并且预览,(必须先调用了openCamera)
if (textureStatus == TEXTURE_STATUS_READY) {
try {
mCamera.setPreviewTexture(mSurfaceTexture);
} catch (IOException e) {
e.printStackTrace();
}
mCamera.startPreview();
mCamera.setPreviewCallback(mPreviewCallback);
status = STATUS_PREVIEWING;
return;
}
}
public void resumePreview() {
mCamera.startPreview();
}
private byte[] currentFrameData;
private Camera.PreviewCallback mPreviewCallback = new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// 在某些机型和某项项目中某些帧的data的数据不符合nv21的格式需要过滤否则后续处理会导致crash
if (data.length != cameraParameters.getPreviewSize().width
* cameraParameters.getPreviewSize().height * 1.5) {
return;
}
currentFrameData = data;
}
};
public void openCamera() {
mCamera = open(isBack);
cameraParameters = mCamera.getParameters();
Camera.Size previewSize = cameraParameters.getPreviewSize();
List<Camera.Size> supportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
Camera.Size size = getPreviewSize(supportedPreviewSizes);
if (previewRotation == 90 || previewRotation == 270) {
this.previewSize[0] = size.height;
this.previewSize[1] = size.width;
} else {
this.previewSize[0] = size.width;
this.previewSize[1] = size.height;
}
previewSize.height = size.height;
if (isBack && cameraParameters.getSupportedFocusModes().contains(
Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
cameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}
cameraParameters.setPreviewSize(size.width, size.height);
mCamera.setDisplayOrientation(previewRotation);
mCamera.setParameters(cameraParameters);
status = STATUS_OPENED;
if (mCameraListener != null) {
mCameraListener.onSwitchCamera();
}
}
public void closeCamera() {
stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
status = STATUS_INIT;
}
@Override
public void stopPreview() {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
status = STATUS_OPENED;
Log.e("literrr", "stoped");
}
@Override
public void switchSide() {
isBack = !isBack;
stopPreview();
closeCamera();
openCamera();
startPreview();
}
private Bitmap convertPreviewDataToBitmap(byte[] data) {
Camera.Size size = cameraParameters.getPreviewSize();
YuvImage img = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
ByteArrayOutputStream os = null;
os = new ByteArrayOutputStream(data.length);
img.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, os);
byte[] jpeg = os.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length);
Bitmap bitmapRotate;
if (isBack) {
bitmapRotate = ImageUtil.createRotateBitmap(bitmap, previewCaptureRotation);
} else {
bitmapRotate = ImageUtil.createMirrorRotateBitmap(bitmap, previewCaptureRotation);
}
try {
os.close();
} catch (IOException e) {
UiLog.info("convertPreviewDataToBitmap close bitmap");
}
return bitmapRotate;
}
@Override
public void takePicture(CameraListener.TakePictureListener listener) {
if (currentFrameData != null) {
Bitmap bitmap = convertPreviewDataToBitmap(currentFrameData);
listener.onTakenPicture(bitmap);
UiLog.info("convert bitmap success");
}
}
@Override
public void setEventListener(CameraListener.CommonListener listener) {
mCameraListener = listener;
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mSurfaceTexture = surface;
textureStatus = TEXTURE_STATUS_READY;
mCameraListener.onSurfaceReady();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
hasDestoryUnexcepted = true;
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
}

View File

@@ -1,27 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.camera;
import android.view.TextureView;
/**
* Created by ruanshimin on 2017/3/29.
*/
public interface ICameraProxy extends TextureView.SurfaceTextureListener {
void openCamera();
void setDisplayRotation(int degree);
void startPreview();
void stopPreview();
void closeCamera();
void switchSide();
int[] getPreviewSize();
void takePicture(CameraListener.TakePictureListener listener);
void setEventListener(CameraListener.CommonListener commonListener);
}

View File

@@ -1,37 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.layout;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* Created by ruanshimin on 2018/5/3.
*/
public class OperationFrameLayout extends RelativeLayout {
private int layoutHeight = 360;
public OperationFrameLayout(@NonNull Context context) {
super(context);
}
public OperationFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public OperationFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, layoutHeight);
setBackgroundColor(Color.BLACK);
}
}

View File

@@ -1,155 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.util;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.util.Log;
/**
* Created by ruanshimin on 2018/5/8.
*/
public class ImageUtil {
private static final String TAG = "CameraExif";
public static Bitmap createRotateBitmap(Bitmap bitmap, int rotation) {
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
return Bitmap.createBitmap(
bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
}
public static Bitmap createMirrorRotateBitmap(Bitmap bitmap, int rotation) {
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
matrix.postScale(-1, 1);
return Bitmap.createBitmap(
bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
}
public static int exifToDegrees(int exifOrientation) {
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
return 90;
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
return 180;
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
return 270;
}
return 0;
}
// Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
public static int getOrientation(byte[] jpeg) {
if (jpeg == null) {
return 0;
}
int offset = 0;
int length = 0;
// ISO/IEC 10918-1:1993(E)
while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
int marker = jpeg[offset] & 0xFF;
// Check if the marker is a padding.
if (marker == 0xFF) {
continue;
}
offset++;
// Check if the marker is SOI or TEM.
if (marker == 0xD8 || marker == 0x01) {
continue;
}
// Check if the marker is EOI or SOS.
if (marker == 0xD9 || marker == 0xDA) {
break;
}
// Get the length and check if it is reasonable.
length = pack(jpeg, offset, 2, false);
if (length < 2 || offset + length > jpeg.length) {
Log.e(TAG, "Invalid length");
return 0;
}
// Break if the marker is EXIF in APP1.
if (marker == 0xE1 && length >= 8
&& pack(jpeg, offset + 2, 4, false) == 0x45786966
&& pack(jpeg, offset + 6, 2, false) == 0) {
offset += 8;
length -= 8;
break;
}
// Skip other markers.
offset += length;
length = 0;
}
// JEITA CP-3451 Exif Version 2.2
if (length > 8) {
// Identify the byte order.
int tag = pack(jpeg, offset, 4, false);
if (tag != 0x49492A00 && tag != 0x4D4D002A) {
Log.e(TAG, "Invalid byte order");
return 0;
}
boolean littleEndian = (tag == 0x49492A00);
// Get the offset and check if it is reasonable.
int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
if (count < 10 || count > length) {
Log.e(TAG, "Invalid offset");
return 0;
}
offset += count;
length -= count;
// Get the count and go through all the elements.
count = pack(jpeg, offset - 2, 2, littleEndian);
while (count-- > 0 && length >= 12) {
// Get the tag and check if it is orientation.
tag = pack(jpeg, offset, 2, littleEndian);
if (tag == 0x0112) {
// We do not really care about type and count, do we?
int orientation = pack(jpeg, offset + 8, 2, littleEndian);
switch (orientation) {
case 1:
return 0;
case 3:
return 180;
case 6:
return 90;
case 8:
return 270;
default:
return 0;
}
}
offset += 12;
length -= 12;
}
}
Log.i(TAG, "Orientation not found");
return 0;
}
private static int pack(byte[] bytes, int offset, int length,
boolean littleEndian) {
int step = 1;
if (littleEndian) {
offset += length - 1;
step = -1;
}
int value = 0;
while (length-- > 0) {
value = (value << 8) | (bytes[offset] & 0xFF);
offset += step;
}
return value;
}
}

View File

@@ -1,14 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.util;
import java.text.DecimalFormat;
/**
* Created by ruanshimin on 2018/5/24.
*/
public class StringUtil {
public static String formatFloatString(float number) {
DecimalFormat df = new DecimalFormat("0.00");
return df.format(number);
}
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.paddle.fastdeploy.app.ui.util;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolManager {
static Timer timerFocus = null;
/*
* 对焦频率
*/
static final long cameraScanInterval = 2000;
/*
* 线程池大小
*/
private static int poolCount = Runtime.getRuntime().availableProcessors();
private static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(poolCount);
private static ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
/**
* 给线程池添加任务
*
* @param runnable 任务
*/
public static void execute(Runnable runnable) {
fixedThreadPool.execute(runnable);
}
/**
* 单独线程任务
*
* @param runnable 任务
*/
public static void executeSingle(Runnable runnable) {
singleThreadPool.execute(runnable);
}
/**
* 创建一个定时对焦的timer任务
*
* @param runnable 对焦代码
* @return Timer Timer对象用来终止自动对焦
*/
public static Timer createAutoFocusTimerTask(final Runnable runnable) {
if (timerFocus != null) {
return timerFocus;
}
timerFocus = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
runnable.run();
}
};
timerFocus.scheduleAtFixedRate(task, 0, cameraScanInterval);
return timerFocus;
}
/**
* 终止自动对焦任务实际调用了cancel方法并且清空对象
* 但是无法终止执行中的任务,需额外处理
*/
public static void cancelAutoFocusTimer() {
if (timerFocus != null) {
timerFocus.cancel();
timerFocus = null;
}
}
}

View File

@@ -1,15 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.util;
import android.util.Log;
/**
* Created by ruanshimin on 2018/5/4.
*/
public class UiLog {
private static final String TAG = "edge_log";
public static void info(String log) {
Log.i(TAG, log);
}
}

View File

@@ -1,4 +1,4 @@
package com.baidu.paddle.fastdeploy.app.ui;
package com.baidu.paddle.fastdeploy.app.ui.view;
import android.content.res.Configuration;
import android.os.Bundle;

View File

@@ -1,4 +1,4 @@
package com.baidu.paddle.fastdeploy.app.ui;
package com.baidu.paddle.fastdeploy.app.ui.view;
import android.content.Context;
import android.graphics.Bitmap;
@@ -15,7 +15,7 @@ import android.opengl.Matrix;
import android.util.AttributeSet;
import android.util.Log;
import com.baidu.paddle.fastdeploy.app.ui.view.Utils;
import com.baidu.paddle.fastdeploy.app.ui.Utils;
import java.io.IOException;
import java.nio.ByteBuffer;

View File

@@ -1,162 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.baidu.paddle.fastdeploy.app.examples.R;
/**
* Created by ruanshimin on 2018/5/7.
*/
public class PreviewDecoratorView extends View {
static final String RUNNING_HINT_TEXT = "对准识别物体,自动识别物体";
static final String STOP_HINT_TEXT = "已暂定实时识别,请点击下方按钮开启";
private String hintText = STOP_HINT_TEXT;
public PreviewDecoratorView(Context context) {
super(context);
}
public PreviewDecoratorView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public PreviewDecoratorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
public void setStatus(boolean isRunning) {
if (isRunning) {
hintText = RUNNING_HINT_TEXT;
} else {
hintText = STOP_HINT_TEXT;
}
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
int offset = 50;
int offsetBottom = 170;
int stokeWidth = 15;
int extendOffset = stokeWidth / 2;
int height = getHeight();
int width = getWidth();
int barSize = 40;
canvas.save();
Paint paintBar = new Paint();
paintBar.setColor(Color.WHITE);
paintBar.setStrokeWidth(stokeWidth);
paintBar.setStyle(Paint.Style.STROKE);
Point leftTop = new Point(offset, offset);
Point rightTop = new Point(width - offset, offset);
Point leftBottom = new Point(offset, height - offsetBottom);
Point rightBottom = new Point(width - offset, height - offsetBottom);
Path path = new Path();
path.moveTo(leftTop.x, leftTop.y + barSize);
path.lineTo(leftTop.x, leftTop.y);
path.lineTo(leftTop.x + barSize, leftTop.y);
path.moveTo(rightTop.x - barSize, leftTop.y);
path.lineTo(rightTop.x, rightTop.y);
path.lineTo(rightTop.x, rightTop.y + barSize);
path.moveTo(leftBottom.x, leftBottom.y - barSize);
path.lineTo(leftBottom.x, leftBottom.y);
path.lineTo(leftBottom.x + barSize, leftBottom.y);
path.moveTo(rightBottom.x - barSize, rightBottom.y);
path.lineTo(rightBottom.x, rightBottom.y);
path.lineTo(rightBottom.x, rightBottom.y - barSize);
// 绘制半透明遮罩
Rect rect = new Rect(0, 0, width, height);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setAlpha(50);
canvas.drawRect(rect, paint);
// 擦除可见部分半透明遮罩
rect = new Rect(leftTop.x - extendOffset, leftTop.y - extendOffset,
rightBottom.x + extendOffset, rightBottom.y + extendOffset);
canvas.clipRect(rect);
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// 绘制四个小角
canvas.drawPath(path, paintBar);
canvas.restore();
// 设置留给hint的位置
rect = new Rect(0, rightBottom.y + extendOffset, width, height);
drawHint(canvas, rect, hintText);
super.onDraw(canvas);
}
public void drawHint(Canvas canvas, Rect rect, String text) {
int textSizePx = 16;
int imageSizePx = 48;
int padInTextAndIcon = 22;
Paint textPaint = new Paint();
textPaint.setTextSize(textSizePx);
textPaint.setColor(Color.WHITE);
textPaint.setTextAlign(Paint.Align.LEFT);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.scan_icon);
float textWidth = getTextWidth(this.getContext(), text, textPaint, textSizePx);
int width = padInTextAndIcon + imageSizePx + (int) textWidth;
int height = imageSizePx;
int startX = rect.left + (rect.width() - width) / 2;
int startY = rect.top + (rect.height() - height) / 2;
Rect srcRect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
Rect destRect = new Rect(startX, startY, startX + imageSizePx, startY + imageSizePx);
Paint mBitPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBitPaint.setFilterBitmap(true);
mBitPaint.setDither(true);
canvas.drawBitmap(bitmap, srcRect, destRect, mBitPaint);
startX += padInTextAndIcon + imageSizePx;
canvas.drawText(text, startX, startY + textSizePx + 23, textPaint);
}
public float getTextWidth(Context context, String text, Paint paint, int textSize) {
float scaledDensity = getResources().getDisplayMetrics().scaledDensity;
paint.setTextSize(scaledDensity * textSize);
return paint.measureText(text);
}
}

View File

@@ -1,144 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.view;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.TextureView;
import com.baidu.paddle.fastdeploy.app.ui.camera.CameraListener;
import com.baidu.paddle.fastdeploy.app.ui.camera.CameraProxy1;
import com.baidu.paddle.fastdeploy.app.ui.camera.ICameraProxy;
/**
* Created by ruanshimin on 2018/5/3.
*/
public class PreviewView extends TextureView {
ICameraProxy mCameraProxy;
private int layoutWidth;
private int layoutHeight;
private int actualHeight;
private int cropHeight;
public PreviewView(Context context) {
super(context);
}
public PreviewView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PreviewView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 手动调用开始预览
*/
public void start() {
if (mCameraProxy != null) {
mCameraProxy.startPreview();
}
}
/**
* 释放摄像头
*/
public void destory() {
if (mCameraProxy != null) {
mCameraProxy.closeCamera();
}
}
/**
* 手动停止
*/
public void stopPreview() {
mCameraProxy.stopPreview();
}
/**
* 设置实际可见layout的长宽
*/
public void setLayoutSize(int width, int height) {
layoutWidth = width;
layoutHeight = height;
}
public void takePicture(final CameraListener.TakePictureListener listener) {
// 裁剪图片
mCameraProxy.takePicture(new CameraListener.TakePictureListener() {
@Override
public void onTakenPicture(Bitmap bitmap) {
Bitmap cropBitmap = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), cropHeight);
listener.onTakenPicture(cropBitmap);
}
});
}
/**
* 切换摄像头面
*/
public void switchSide() {
mCameraProxy.switchSide();
}
public int getActualHeight() {
return actualHeight;
}
private void setDisplayDegree() {
int rotation = ((Activity) this.getContext()).getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
default:
degrees = 0;
}
mCameraProxy.setDisplayRotation(degrees);
}
private void refreshCropHeight() {
int[] size = mCameraProxy.getPreviewSize();
actualHeight = (int) (((float) size[1] / size[0]) * layoutWidth);
cropHeight = (int) (((float) layoutHeight / layoutWidth) * size[0]);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mCameraProxy == null) {
mCameraProxy = new CameraProxy1(layoutWidth, layoutHeight);
setDisplayDegree();
setSurfaceTextureListener(mCameraProxy);
mCameraProxy.openCamera();
refreshCropHeight();
mCameraProxy.setEventListener(new CameraListener.CommonListener() {
@Override
public void onSurfaceReady() {
mCameraProxy.startPreview();
}
@Override
public void onSwitchCamera() {
refreshCropHeight();
}
});
}
}
}

View File

@@ -1,381 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.baidu.paddle.fastdeploy.app.ui.util.StringUtil;
import com.baidu.paddle.fastdeploy.app.ui.view.model.BasePolygonResultModel;
import com.baidu.paddle.fastdeploy.app.ui.view.model.PoseViewResultModel;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
/**
* Created by ruanshimin on 2018/5/15.
*/
public class ResultMaskView extends View {
private static final int[][] COLOR_MAP_DEF = {
{0, 0, 0},
{244, 35, 232},
{70, 70, 70},
{102, 102, 156},
{190, 153, 153},
{153, 153, 153},
{250, 170, 30},
{220, 220, 0},
{107, 142, 35},
{152, 251, 152},
{70, 130, 180},
{220, 20, 60},
{255, 0, 0},
{0, 0, 142},
{0, 0, 70},
{0, 60, 100},
{0, 80, 100},
{0, 0, 230},
{119, 11, 32},
{128, 64, 128}
};
private float sizeRatio;
private List<BasePolygonResultModel> mResultModelList;
private Point originPt = new Point();
private int imgWidth;
private int imgHeight;
private Paint textPaint;
private Handler handler;
public void setHandler(Handler mHandler) {
handler = mHandler;
}
public ResultMaskView(Context context) {
super(context);
}
private Map<Integer, Paint> paintFixPool = new HashMap<>();
public ResultMaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
public void setPolygonListInfo(List<BasePolygonResultModel> modelList, int width, int height) {
imgWidth = width;
imgHeight = height;
mResultModelList = modelList;
handler.post(new Runnable() {
@Override
public void run() {
invalidate();
}
});
}
public void clear() {
mResultModelList = null;
handler.post(new Runnable() {
@Override
public void run() {
invalidate();
}
});
}
private void preCaculate() {
float ratio = (float) getMeasuredWidth() / (float) getMeasuredHeight();
float ratioBitmap = (float) imgWidth / (float) imgHeight;
// | |#####| |模式
if (ratioBitmap < ratio) {
sizeRatio = (float) getMeasuredHeight() / (float) imgHeight;
int x = (int) (getMeasuredWidth() - sizeRatio * imgWidth) / 2;
originPt.set(x, 0);
} else {
// ------------
//
// ------------
// ############
// ------------
//
// ------------
sizeRatio = (float) getMeasuredWidth() / (float) imgWidth;
int y = (int) (getMeasuredHeight() - sizeRatio * imgHeight) / 2;
originPt.set(0, y);
}
}
private Map<Integer, Paint> paintRandomPool = new HashMap<>();
public ResultMaskView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
textPaint = new Paint();
textPaint.setTextSize(30);
textPaint.setARGB(255, 255, 255, 255);
}
private Paint getRandomMaskPaint(int index) {
if (paintRandomPool.containsKey(index)) {
return paintRandomPool.get(index);
}
int[] seed = new int[3];
int offset = index % 3;
seed[offset] = 255;
Paint paint = new Paint();
Random rnd = new Random();
paint.setARGB(170,
(rnd.nextInt(255) + seed[0]) / 2,
(rnd.nextInt(255) + seed[1]) / 2,
(rnd.nextInt(255) + seed[2]) / 2);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paintRandomPool.put(index, paint);
return paint;
}
private Paint getFixColorPaint(int colorId) {
// float alpha = 90;
String[] colors = {"#FF0000", "#FF0000", "#00FF00", "#0000FF", "#FF00FF"};
int index = colorId % colors.length;
if (paintFixPool.containsKey(index)) {
return paintFixPool.get(index);
}
int color = Color.parseColor(colors[index]);
Paint paint = new Paint();
paint.setColor(color);
//paint.setAlpha(90);
paintFixPool.put(index, paint);
return paint;
}
@Override
protected void onDraw(Canvas canvas) {
// 实时识别的时候第一次渲染
if (mResultModelList == null) {
super.onDraw(canvas);
return;
}
preCaculate();
int stokeWidth = 5;
int fontSize = 38;
int labelPadding = 5;
int labelHeight = 46 + 2 * labelPadding;
Paint paint = new Paint();
paint.setColor(Color.parseColor("#3B85F5"));
paint.setStrokeWidth(stokeWidth);
paint.setStyle(Paint.Style.STROKE);
Paint paintFillAlpha = new Paint();
paintFillAlpha.setStyle(Paint.Style.FILL);
paintFillAlpha.setColor(Color.parseColor("#3B85F5"));
paintFillAlpha.setAlpha(50);
Paint paintFill = new Paint();
paintFill.setStyle(Paint.Style.FILL);
paintFill.setColor(Color.parseColor("#3B85F5"));
Paint paintText = new Paint();
paintText.setColor(Color.WHITE);
paintText.setTextAlign(Paint.Align.LEFT);
paintText.setTextSize(fontSize);
DecimalFormat df = new DecimalFormat("0.00");
List<Float> points;
for (int i = 0; i < mResultModelList.size(); i++) {
BasePolygonResultModel model = mResultModelList.get(i);
Path path = new Path();
List<Point> polygon = model.getBounds(sizeRatio, originPt);
path.moveTo(polygon.get(0).x, polygon.get(0).y);
for (int j = 1; j < polygon.size(); j++) {
path.lineTo(polygon.get(j).x, polygon.get(j).y);
}
path.close();
if (model.isDrawPoints()) {
Paint paintFillPoint = new Paint();
paintFillPoint.setStyle(Paint.Style.FILL_AND_STROKE);
paintFillPoint.setColor(Color.YELLOW);
List<Point> polygonPoints = model.getBounds(sizeRatio, originPt);
for (Point p : polygonPoints) {
canvas.drawCircle(p.x, p.y, 10 * sizeRatio, paintFillPoint);
}
}
// 绘制框
if (!model.isHasMask()) {
if (model instanceof PoseViewResultModel && model.isHasGroupColor()) {
paint = getFixColorPaint(model.getColorId());
paint.setStrokeWidth(stokeWidth);
paint.setStyle(Paint.Style.STROKE);
paint.setAlpha(90);
}
canvas.drawPath(path, paint);
canvas.drawPath(path, paintFillAlpha);
if (model.isRect()) {
Rect rect = model.getRect(sizeRatio, originPt);
canvas.drawRect(new Rect(rect.left, rect.top, rect.right,
rect.top + labelHeight), paintFill);
}
}
if (model.isRect()) {
Rect rect = model.getRect(sizeRatio, originPt);
canvas.drawText(model.getName() + " " + StringUtil.formatFloatString(model.getConfidence()),
rect.left + labelPadding,
rect.top + fontSize + labelPadding, paintText);
}
if (model.isTextOverlay()) {
canvas.drawText(model.getName(),
polygon.get(0).x, polygon.get(0).y, textPaint);
}
// 绘制mask
if (model.isHasMask()) {
if (!model.isSemanticMask()) {
// 实例分割绘制
Paint paintMask = getRandomMaskPaint(model.getColorId());
points = new ArrayList<>();
byte[] maskData = model.getMask();
for (int w = 0; w < imgWidth * sizeRatio; w++) {
for (int h = 0; h < imgHeight * sizeRatio; h++) {
int realX = (int) (w / sizeRatio);
int realY = (int) (h / sizeRatio);
int offset = imgWidth * realY + realX;
if (offset < maskData.length && maskData[offset] == 1) {
points.add(originPt.x + (float) w);
points.add(originPt.y + (float) h);
}
}
}
float[] ptft = new float[points.size()];
for (int j = 0; j < points.size(); j++) {
ptft[j] = points.get(j);
}
canvas.drawPoints(ptft, paintMask);
} else {
// 语义分割绘制
drawSemanticMask(canvas, model);
}
}
}
super.onDraw(canvas);
}
/**
* 语义分割基于mask不同值绘制颜色
*/
private void drawSemanticMask(Canvas canvas, BasePolygonResultModel model) {
List<ColorPointsPair> colorPointsPairList = new ArrayList<>();
for (int[] rgb : COLOR_MAP_DEF) {
Paint paint = new Paint();
paint.setARGB(170, rgb[0], rgb[1], rgb[2]);
colorPointsPairList.add(new ColorPointsPair(paint));
}
byte[] maskData = model.getMask();
for (int w = 0; w < imgWidth * sizeRatio; w++) {
for (int h = 0; h < imgHeight * sizeRatio; h++) {
int realX = (int) (w / sizeRatio);
int realY = (int) (h / sizeRatio);
int offset = imgWidth * realY + realX;
byte label = maskData[offset];
if (label >= colorPointsPairList.size()) {
for (int i = colorPointsPairList.size(); i <= label; i++ ) {
Paint newPaint = getRandomMaskPaint(i);
colorPointsPairList.add(new ColorPointsPair(newPaint));
}
}
colorPointsPairList.get(label).addPoint(originPt.x + (float) w);
colorPointsPairList.get(label).addPoint(originPt.y + (float) h);
}
}
for (ColorPointsPair pair : colorPointsPairList) {
float[] points = pair.getPointsArray();
if (points != null) {
canvas.drawPoints(points, pair.getPaint());
}
}
}
/**
* 用于分割模型,一个颜色对应一系列点
*/
private class ColorPointsPair {
private final Paint paint;
private List<Float> points;
public ColorPointsPair(Paint paint) {
this.paint = paint;
}
public void addPoint(float point) {
if (points == null) {
points = new ArrayList<>();
}
points.add(point);
}
public float[] getPointsArray() {
if (points == null || points.size() == 0) {
return null;
}
float[] array = new float[points.size()];
for (int i = 0; i < points.size(); i++) {
array[i] = points.get(i);
}
return array;
}
public Paint getPaint() {
return paint;
}
}
}

View File

@@ -10,9 +10,9 @@ import android.widget.ArrayAdapter;
import android.widget.TextView;
import com.baidu.paddle.fastdeploy.app.examples.R;
import com.baidu.paddle.fastdeploy.app.ui.util.StringUtil;
import com.baidu.paddle.fastdeploy.app.ui.view.model.BaseResultModel;
import java.text.DecimalFormat;
import java.util.List;
/**
@@ -41,7 +41,12 @@ public class DetectResultAdapter extends ArrayAdapter<BaseResultModel> {
TextView confidenceText = (TextView) view.findViewById(R.id.confidence);
indexText.setText(String.valueOf(model.getIndex()));
nameText.setText(String.valueOf(model.getName()));
confidenceText.setText(StringUtil.formatFloatString(model.getConfidence()));
confidenceText.setText(formatFloatString(model.getConfidence()));
return view;
}
public static String formatFloatString(float number) {
DecimalFormat df = new DecimalFormat("0.00");
return df.format(number);
}
}

View File

@@ -1,149 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.view.model;
import android.graphics.Point;
import android.graphics.Rect;
import java.util.ArrayList;
import java.util.List;
public class BasePolygonResultModel extends BaseResultModel {
private int colorId;
private boolean isRect;
private boolean isTextOverlay;
private boolean isHasGroupColor = false;
private boolean isDrawPoints = false;
public boolean isTextOverlay() {
return isTextOverlay;
}
public void setTextOverlay(boolean textOverlay) {
isTextOverlay = textOverlay;
}
public int getColorId() {
return colorId;
}
public void setColorId(int colorId) {
this.colorId = colorId;
}
private byte[] mask;
/**
* 是否是语义分割mask
*/
private boolean semanticMask;
private Rect rect;
BasePolygonResultModel() {
super();
}
BasePolygonResultModel(int index, String name, float confidence, Rect bounds) {
super(index, name, confidence);
parseFromRect(bounds);
}
BasePolygonResultModel(int index, String name, float confidence, List<Point> bounds) {
super(index, name, confidence);
this.bounds = bounds;
}
public Rect getRect() {
return rect;
}
public Rect getRect(float ratio, Point origin) {
return new Rect((int) (origin.x + rect.left * ratio),
(int) (origin.y + rect.top * ratio),
(int) (origin.x + rect.right * ratio),
(int) (origin.y + rect.bottom * ratio));
}
private void parseFromRect(Rect rect) {
Point ptTL = new Point(rect.left, rect.top);
Point ptTR = new Point(rect.right, rect.top);
Point ptRB = new Point(rect.right, rect.bottom);
Point ptLB = new Point(rect.left, rect.bottom);
this.bounds = new ArrayList<>();
this.bounds.add(ptTL);
this.bounds.add(ptTR);
this.bounds.add(ptRB);
this.bounds.add(ptLB);
this.rect = rect;
isRect = true;
}
public boolean isRect() {
return isRect;
}
public void setRect(boolean rect) {
isRect = rect;
}
public byte[] getMask() {
return mask;
}
public void setMask(byte[] mask) {
this.mask = mask;
}
public void setSemanticMask(boolean semanticMask) {
this.semanticMask = semanticMask;
}
public boolean isSemanticMask() {
return semanticMask;
}
private List<Point> bounds;
public List<Point> getBounds() {
return bounds;
}
public List<Point> getBounds(float ratio, Point origin) {
List<Point> pointList = new ArrayList<>();
for (Point pt : bounds) {
int nx = (int) (origin.x + pt.x * ratio);
int ny = (int) (origin.y + pt.y * ratio);
pointList.add(new Point(nx, ny));
}
return pointList;
}
public void setBounds(List<Point> bounds) {
this.bounds = bounds;
}
public void setBounds(Rect bounds) {
parseFromRect(bounds);
}
public boolean isHasMask() {
return (mask != null);
}
public boolean isHasGroupColor() {
return isHasGroupColor;
}
public void setHasGroupColor(boolean hasGroupColor) {
isHasGroupColor = hasGroupColor;
}
public boolean isDrawPoints() {
return isDrawPoints;
}
public void setDrawPoints(boolean drawPoints) {
isDrawPoints = drawPoints;
}
}

View File

@@ -1,11 +0,0 @@
package com.baidu.paddle.fastdeploy.app.ui.view.model;
public class PoseViewResultModel extends BasePolygonResultModel {
public PoseViewResultModel() {
super();
setRect(false);
setTextOverlay(false);
setDrawPoints(true);
}
}

View File

@@ -12,7 +12,7 @@
android:layout_height="match_parent"
android:background="@color/colorWindow">
<com.baidu.paddle.fastdeploy.app.ui.CameraSurfaceView
<com.baidu.paddle.fastdeploy.app.ui.view.CameraSurfaceView
android:id="@+id/sv_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@@ -4,11 +4,11 @@
android:layout_height="match_parent">
<include
layout="@layout/camera_page"
layout="@layout/default_camera_page"
android:id="@+id/camera_page"></include>
<include
layout="@layout/result_page"
layout="@layout/default_result_page"
android:id="@+id/result_page"
android:visibility="gone"></include>
</FrameLayout>

View File

@@ -54,8 +54,8 @@
</LinearLayout>
</com.baidu.paddle.fastdeploy.app.ui.layout.ActionBarLayout>
<!-- -->
<com.baidu.paddle.fastdeploy.app.ui.CameraSurfaceView
<!---->
<com.baidu.paddle.fastdeploy.app.ui.view.CameraSurfaceView
android:id="@+id/sv_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@@ -46,10 +46,6 @@
android:layout_height="match_parent"
android:background="@color/bk_result_image_padding" />
<com.baidu.paddle.fastdeploy.app.ui.view.ResultMaskView
android:id="@+id/result_mask"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<TextView

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="160dp"
android:layout_height="200dp"
android:layout_gravity="right"
android:layout_marginTop="80px"
android:layout_marginRight="80px">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/bk_blue"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.6"
style="@style/list_result_popview_tablehead_style"
android:text="@string/result_table_header_name" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.4"
android:gravity="right"
android:layout_marginRight="30px"
style="@style/list_result_popview_tablehead_style"
android:text="@string/result_table_header_confidence" />
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.baidu.paddle.fastdeploy.app.ui.view.ResultListView
android:id="@+id/result_list_popview"
android:layout_width="match_parent"
android:layout_height="match_parent"></com.baidu.paddle.fastdeploy.app.ui.view.ResultListView>.
</ScrollView>
</LinearLayout>