CameraX 分析/相机 onPreviewFrame
CameraX Analysis / Camera onPreviewFrame
在CameraX Analysis中,setTargetResolution(new Size(2560, 800),但在Analyzer中imageProxy.getImage.getWidth=1280 and getHeight=400, and YUVToByte(imageProxy.getImage).length()=768000。在Camera中,parameter.setPreviewSize(2560, 800)然后byte[].length在onPreviewFrame中是3072000(等于768000*(2560/1280)*(800/400))。如何让CameraX Analyzer imageProxy.getImage.getWidth and getHeight = 2560 and 800, and YUVToByte(ImageProxy.getImage).length()=3072000? 在CameraX的onPreviewFrame()中,res总是=null,在Camera的onPreviewFrame()中,res可以得到currect值,有什么不同CameraX 和 Camera 之间的区别?在 CameraX 中我应该做什么?
CameraX:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
try {
copyDataBase();
} catch (IOException e) {
e.printStackTrace();
}
getSupportActionBar().hide();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
viewFinder = findViewById(R.id.previewView);
executor = Executors.newSingleThreadExecutor();
if (!allPermissionGranted()) {
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
}
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
width = metric.widthPixels;
height = metric.heightPixels;
l = 100;
r = width - 100;
ntmpH = (r - l) * 58 / 100;
t = (height - ntmpH) / 2;
b = t + ntmpH;
double proportion = (double) width / (double) preHeight;
double hproportion = (double) height / (double) preWidth;
l = (int) (l / proportion);
t = (int) (t / hproportion);
r = (int) (r / proportion);
b = (int) (b / hproportion);
m_ROI[0] = l;
m_ROI[1] = t;
m_ROI[2] = r;
m_ROI[3] = b;
cameraProviderFuture = processCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
@SuppressLint("RestrictedApi") Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder().
requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setTargetResolution(new Size(2560, 800))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.setTargetRotation(Surface.ROTATION_90)
.build();
imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
@SuppressLint("UnsafeExperimentalUsageError")
@Override
public void analyze(@NonNull ImageProxy imageProxy) {
if (imageProxy.getFormat() == ImageFormat.YUV_420_888) {
image = imageProxy.getImage();
bIninKernal();
Log.d("Size ", image.getWidth() + "/" + image.getHeight());
onPreviewFrame(YUVToByte(image));
} else {
Log.d("Status ", "照片格式錯誤" + imageProxy.getFormat());
}
imageProxy.close();
}
});
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);
preview.setSurfaceProvider(viewFinder.createSurfaceProvider());
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}, ContextCompat.getMainExecutor(this));
}
@NonNull
@Override
public CameraXConfig getCameraXConfig() {
return Camera2Config.defaultConfig();
}
private boolean allPermissionGranted() {
for (String permission : REQUIRED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
private byte[] YUVToByte(Image image) {
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer0 = planes[0].getBuffer();
ByteBuffer buffer1 = planes[1].getBuffer();
ByteBuffer buffer2 = planes[2].getBuffer();
int width = image.getWidth();
int height = image.getHeight();
byte[] data = new byte[image.getWidth() * image.getHeight() * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];
byte[] rowData1 = new byte[planes[1].getRowStride()];
byte[] rowData2 = new byte[planes[2].getRowStride()];
int bytesPerPixel = ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8;
// loop via rows of u/v channels
int offsetY = 0;
int sizeY = width * height * bytesPerPixel;
int sizeUV = (width * height * bytesPerPixel) / 4;
for (int row = 0; row < height; row++) {
// fill data for Y channel, two row
{
int length = bytesPerPixel * width;
buffer0.get(data, offsetY, length);
if (height - row != 1)
buffer0.position(buffer0.position() + planes[0].getRowStride() - length);
offsetY += length;
}
if (row >= height / 2)
continue;
{
int uvlength = planes[1].getRowStride();
if ((height / 2 - row) == 1) {
uvlength = width / 2 - planes[1].getPixelStride() + 1;
}
buffer1.get(rowData1, 0, uvlength);
buffer2.get(rowData2, 0, uvlength);
// fill data for u/v channels
for (int col = 0; col < width / 2; ++col) {
// u channel
data[sizeY + (row * width) / 2 + col] = rowData1[col * planes[1].getPixelStride()];
// v channel
data[sizeY + sizeUV + (row * width) / 2 + col] = rowData2[col * planes[2].getPixelStride()];
}
}
}
return data;
}
private void bIninKernal() {
api = new LPR();
String FilePath = Environment.getExternalStorageDirectory().toString() + "/lpr.key";
int nRet = api.Init(this, m_ROI[0], m_ROI[1], m_ROI[2], m_ROI[3], preHeight, preWidth, FilePath);
if (nRet != 0) {
bInitKernal = false;
Log.d("Status ", "相機開啟失敗");
} else {
bInitKernal = true;
}
}
private void onPreviewFrame(byte[] data) {
bIninKernal();
tackData = data;
Log.d("data length ", data.length + "");
resultStr = "";
if (!leaving && bInitKernal) {
byte[] result;
String res = "";
result = api.VideoRec(tackData, 1280, 400, 1);
try {
res = new String(result, "gb2312");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (res != null && !"".equals(res.trim())) {
resultStr = res.trim();
if (resultStr != "") {
leaving = true;
MediaActionSound sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
Log.d("Status ", "辨識成功");
Log.d("車牌號碼", resultStr);
Thread thread = new Thread(Image_update);
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent intent = new Intent(MainActivity2.this, MainActivity.class);
intent.putExtra("result", resultStr);
Log.d("result", resultStr);
setResult(1, intent);
finish();
}
} else {
Log.d("Status ", "未分辨車牌號碼,請重拍");
}
}
}
public void copyDataBase() throws IOException {
// Common common = new Common();
// 取得SK卡路徑/lpr.key
String dst = Environment.getExternalStorageDirectory().toString() + "/lpr.key";
File file = new File(dst);
if (!file.exists()) {
// file.createNewFile();
} else {
file.delete();
}
Log.d("File Name", file.toString());
try {
InputStream myInput = getAssets().open("lpr.key");
OutputStream myOutput = new FileOutputStream(dst);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch (Exception e) {
System.out.println("lpr.key" + "is not found");
}
}
private Runnable Image_update = new Runnable() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://0d9dccd7eac8.ngrok.io/")
.addConverterFactory(GsonConverterFactory.create())
.build();
MyAPIService myAPIService = retrofit.create(MyAPIService.class);
@Override
public void run() {
Log.d("Status ", "run");
Log.d("resultStr ", resultStr);
String url = "D:\Images\license_plate\";
String imgStr = bitmap2base64(toBitmap(image));
LicensePlate licensePlate = new LicensePlate();
licensePlate.setsPlate(resultStr);
licensePlate.setsPicPosition(url + resultStr);
licensePlate.setImgStr(imgStr);
Call<LicensePlate> call = myAPIService.uploadLicensePlate(licensePlate);
call.enqueue(new Callback<LicensePlate>() {
@Override
public void onResponse(Call<LicensePlate> call, Response<LicensePlate> response) {
if(response.isSuccessful()){
Log.d("Status ", "照片上傳成功");
}else{
Log.d("Status ", "照片上傳失敗");
Log.d("response code ", response.code() + "");
}
}
@Override
public void onFailure(Call<LicensePlate> call, Throwable t) {
Log.d("Status ", "onFailure");
Log.d("Message ", t.getMessage());
}
});
}
};
private String bitmap2base64(Bitmap bitmap){
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT).trim().replaceAll("\n", "").replaceAll("\r", "");
}
private Bitmap toBitmap(Image image) {
Image.Plane[] planes = image.getPlanes();
ByteBuffer yBuffer = planes[0].getBuffer();
ByteBuffer uBuffer = planes[1].getBuffer();
ByteBuffer vBuffer = planes[2].getBuffer();
int ySize = yBuffer.remaining();
int uSize = uBuffer.remaining();
int vSize = vBuffer.remaining();
byte[] nv21 = new byte[ySize + uSize + vSize];
//U and V are swapped
yBuffer.get(nv21, 0, ySize);
vBuffer.get(nv21, ySize, vSize);
uBuffer.get(nv21, ySize + vSize, uSize);
YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 75, out);
byte[] imageBytes = out.toByteArray();
return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
}
}
相机
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 隐藏标题
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int metricwidth = metric.widthPixels; // 屏幕宽度(像素)
int metricheight = metric.heightPixels; // 屏幕高度(像素)
try {
copyDataBase();
} catch (IOException e) {
e.printStackTrace();
}
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);// 竖屏
Configuration cf= this.getResources().getConfiguration(); //获取设置的配置信息
int noriention=cf.orientation;
requestWindowFeature(Window.FEATURE_NO_TITLE);// 隐藏标题
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
// // 屏幕常亮
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_lpr2);
findView();
}
private void findView() {
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
re_c = (RelativeLayout) findViewById(R.id.re_c);
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
width = metric.widthPixels; // 屏幕宽度(像素)
height = metric.heightPixels; // 屏幕高度(像素)
if(myView==null)
{
if (isFatty)
{
myView = new LPRfinderView2(LPR2Activity.this, width, height, isFatty);
}
else
{
myView = new LPRfinderView2(LPR2Activity.this, width, height);
}
re_c.addView(myView);
}
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(LPR2Activity.this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.setFocusable(true);
//surfaceView.invali.date();
}
public void copyDataBase() throws IOException {
// Common common = new Common();
// 取得SK卡路徑/lpr.key
String dst = Environment.getExternalStorageDirectory().toString() + "/lpr.key";
File file = new File(dst);
if (!file.exists()) {
// file.createNewFile();
} else {
file.delete();
}
Log.d("File Name", file.toString());
try {
InputStream myInput = getAssets().open("lpr.key");
OutputStream myOutput = new FileOutputStream(dst);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch (Exception e) {
System.out.println("lpr.key" + "is not found");
}
}
public void surfaceCreated(SurfaceHolder holder) {
if (mycamera == null) {
try {
mycamera = Camera.open();
} catch (Exception e) {
e.printStackTrace();
String mess = "打开摄像头失败";
Toast.makeText(getApplicationContext(), mess, Toast.LENGTH_LONG).show();
return;
}
}
if(mycamera!=null)
{
try {
mycamera.setPreviewDisplay(holder);
timer2 = new Timer();
if (timer == null)
{
timer = new TimerTask()
{
public void run()
{
if (mycamera != null)
{
try
{
mycamera.autoFocus(new AutoFocusCallback()
{
public void onAutoFocus(boolean success, Camera camera)
{
}
});
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
};
}
timer2.schedule(timer, 500, 2500);
initCamera();
//mycamera.startPreview();
//mycamera.autoFocus(null);
} catch (IOException e) {
e.printStackTrace();
}
}
if(api==null)
{
api= new LPR();
String FilePath =Environment.getExternalStorageDirectory().toString()+"/lpr.key";
int nRet = api.Init(this,m_ROI[0], m_ROI[1], m_ROI[2], m_ROI[3], preHeight, preWidth,FilePath);
if(nRet!=0)
{
Toast.makeText(getApplicationContext(), "啟動失敗,請調整時間", Toast.LENGTH_SHORT).show();
Log.d("nRet ", nRet + "");
bInitKernal =false;
}
else
{
bInitKernal=true;
}
}
if(alertDialog==null){
alertDialog = new AlertDialog.Builder(this).create();
alertDialoginfo = new AlertDialog.Builder(this).create();
}
}
@Override
public void surfaceChanged(final SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
try {
if (mycamera != null) {
mycamera.setPreviewCallback(null);
mycamera.stopPreview();
mycamera.release();
mycamera = null;
}
} catch (Exception e) {
}
if(bInitKernal){
bInitKernal=false;
api = null;
}
if(toast!=null){
toast.cancel();
toast = null;
}
if(timer2!=null){
timer2.cancel();
timer2=null;
}
if(alertDialog!=null)
{
alertDialog.dismiss();
alertDialog.cancel();
alertDialog=null;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
try {
if (mycamera != null) {
mycamera.setPreviewCallback(null);
mycamera.stopPreview();
mycamera.release();
mycamera = null;
}
} catch (Exception e) {
e.printStackTrace();
}
if(bInitKernal)
{
bInitKernal=false;
api = null;
}
finish();
if(toast!=null){
toast.cancel();
toast=null;
}
if(timer2!=null){
timer2.cancel();
timer2=null;
}
if(alertDialog!=null)
{
alertDialog.cancel();
alertDialog=null;
}
}
return super.onKeyDown(keyCode, event);
}
@TargetApi(14)
private void initCamera() {
Camera.Parameters parameters = mycamera.getParameters();
List<Camera.Size> list = parameters.getSupportedPreviewSizes();
preWidth = list.get(4).width;
preHeight = list.get(4).height;
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setPreviewSize(preWidth,preHeight);
if (!bROI) {
int l,t,r,b;
l = 100;
r = width-100;
int ntmpH =(r-l)*58/100;
t = (height-ntmpH)/2;
b = t+ntmpH;
double proportion = (double) width / (double) preHeight;
double hproportion=(double)height/(double) preWidth;
l = (int) (l /proportion);
t = (int) (t /hproportion);
r = (int) (r /proportion);
b = (int) (b / hproportion);
m_ROI[0]=l;
m_ROI[1]=t;
m_ROI[2]=r;
m_ROI[3]=b;
bROI = true;
}
if (parameters.getSupportedFocusModes().contains(
parameters.FOCUS_MODE_AUTO))
{
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);// 1连续对焦
}
mycamera.setPreviewCallback(LPR2Activity.this);
mycamera.setParameters(parameters);
mycamera.setDisplayOrientation(90); //一般機種
mycamera.startPreview();
}
public void onPreviewFrame(byte[] data, Camera camera) {
tackData = data;
Log.d("data length ", data.length + "");
ByteArrayInputStream bis = new ByteArrayInputStream(data);
resultStr = "";
if (!leaving&& bInitKernal ) {
Log.d("Status ", "開始判斷");
byte result[];//[] = new byte[10];
String res="";
result = api.VideoRec(tackData, preWidth, preHeight, 1);
Log.d("preWidth ", preWidth + "");
Log.d("preHeight", preHeight + "");
Log.d("width ", width + "");
Log.d("height", height + "");
try {
res = new String(result,"gb2312");
Log.d("try ", res);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
Log.d("Exception ", e.getMessage());
e.printStackTrace();
}
Log.d("res ", res);
if(res!=null&&!"".equals(res.trim()))
{
Camera.Parameters parameters = mycamera.getParameters();
resultStr =res.trim();
if (resultStr != "") {
leaving = true;
//拍照音效
MediaActionSound sound = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
}
Intent intent = new Intent();
intent.putExtra("strPltNo",resultStr);
setResult(2,intent);
finish();
}else{
Log.d("Status ", "未分配車牌號碼,請重拍");
}
}
}
}
@RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
public String pictureName() {
String str = "";
Time t = new Time();
t.setToNow(); // 取得系统时间。
int year = t.year;
int month = t.month + 1;
int date = t.monthDay;
int hour = t.hour; // 0-23
int minute = t.minute;
int second = t.second;
if (month < 10)
str = String.valueOf(year) + "0" + String.valueOf(month);
else {
str = String.valueOf(year) + String.valueOf(month);
}
if (date < 10)
str = str + "0" + String.valueOf(date + "_");
else {
str = str + String.valueOf(date + "_");
}
if (hour < 10)
str = str + "0" + String.valueOf(hour);
else {
str = str + String.valueOf(hour);
}
if (minute < 10)
str = str + "0" + String.valueOf(minute);
else {
str = str + String.valueOf(minute);
}
if (second < 10)
str = str + "0" + String.valueOf(second);
else {
str = str + String.valueOf(second);
}
return str;
}
public void Leave(View view) {
Intent intent = new Intent();
intent.putExtra("strPltNo","");
setResult(3,intent);
finish();
}
}
CameraX Log
Camera Log
关于图像分析分辨率,ImageAnalysis.Builder.setTargetResolution()
的文档指出:
The maximum available resolution that could be selected for an
ImageAnalysis is limited to be under 1080p.
因此,将尺寸设置为 2560x800 不会如您所愿。在 return 中,CameraX 似乎正在选择与您请求的纵横比相同的最大 ImageAnalysis
分辨率 (2560/800 = 1280/400)。
在CameraX Analysis中,setTargetResolution(new Size(2560, 800),但在Analyzer中imageProxy.getImage.getWidth=1280 and getHeight=400, and YUVToByte(imageProxy.getImage).length()=768000。在Camera中,parameter.setPreviewSize(2560, 800)然后byte[].length在onPreviewFrame中是3072000(等于768000*(2560/1280)*(800/400))。如何让CameraX Analyzer imageProxy.getImage.getWidth and getHeight = 2560 and 800, and YUVToByte(ImageProxy.getImage).length()=3072000? 在CameraX的onPreviewFrame()中,res总是=null,在Camera的onPreviewFrame()中,res可以得到currect值,有什么不同CameraX 和 Camera 之间的区别?在 CameraX 中我应该做什么?
CameraX:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
try {
copyDataBase();
} catch (IOException e) {
e.printStackTrace();
}
getSupportActionBar().hide();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
viewFinder = findViewById(R.id.previewView);
executor = Executors.newSingleThreadExecutor();
if (!allPermissionGranted()) {
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
}
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
width = metric.widthPixels;
height = metric.heightPixels;
l = 100;
r = width - 100;
ntmpH = (r - l) * 58 / 100;
t = (height - ntmpH) / 2;
b = t + ntmpH;
double proportion = (double) width / (double) preHeight;
double hproportion = (double) height / (double) preWidth;
l = (int) (l / proportion);
t = (int) (t / hproportion);
r = (int) (r / proportion);
b = (int) (b / hproportion);
m_ROI[0] = l;
m_ROI[1] = t;
m_ROI[2] = r;
m_ROI[3] = b;
cameraProviderFuture = processCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
@SuppressLint("RestrictedApi") Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder().
requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setTargetResolution(new Size(2560, 800))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.setTargetRotation(Surface.ROTATION_90)
.build();
imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
@SuppressLint("UnsafeExperimentalUsageError")
@Override
public void analyze(@NonNull ImageProxy imageProxy) {
if (imageProxy.getFormat() == ImageFormat.YUV_420_888) {
image = imageProxy.getImage();
bIninKernal();
Log.d("Size ", image.getWidth() + "/" + image.getHeight());
onPreviewFrame(YUVToByte(image));
} else {
Log.d("Status ", "照片格式錯誤" + imageProxy.getFormat());
}
imageProxy.close();
}
});
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);
preview.setSurfaceProvider(viewFinder.createSurfaceProvider());
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}, ContextCompat.getMainExecutor(this));
}
@NonNull
@Override
public CameraXConfig getCameraXConfig() {
return Camera2Config.defaultConfig();
}
private boolean allPermissionGranted() {
for (String permission : REQUIRED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
private byte[] YUVToByte(Image image) {
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer0 = planes[0].getBuffer();
ByteBuffer buffer1 = planes[1].getBuffer();
ByteBuffer buffer2 = planes[2].getBuffer();
int width = image.getWidth();
int height = image.getHeight();
byte[] data = new byte[image.getWidth() * image.getHeight() * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];
byte[] rowData1 = new byte[planes[1].getRowStride()];
byte[] rowData2 = new byte[planes[2].getRowStride()];
int bytesPerPixel = ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8;
// loop via rows of u/v channels
int offsetY = 0;
int sizeY = width * height * bytesPerPixel;
int sizeUV = (width * height * bytesPerPixel) / 4;
for (int row = 0; row < height; row++) {
// fill data for Y channel, two row
{
int length = bytesPerPixel * width;
buffer0.get(data, offsetY, length);
if (height - row != 1)
buffer0.position(buffer0.position() + planes[0].getRowStride() - length);
offsetY += length;
}
if (row >= height / 2)
continue;
{
int uvlength = planes[1].getRowStride();
if ((height / 2 - row) == 1) {
uvlength = width / 2 - planes[1].getPixelStride() + 1;
}
buffer1.get(rowData1, 0, uvlength);
buffer2.get(rowData2, 0, uvlength);
// fill data for u/v channels
for (int col = 0; col < width / 2; ++col) {
// u channel
data[sizeY + (row * width) / 2 + col] = rowData1[col * planes[1].getPixelStride()];
// v channel
data[sizeY + sizeUV + (row * width) / 2 + col] = rowData2[col * planes[2].getPixelStride()];
}
}
}
return data;
}
private void bIninKernal() {
api = new LPR();
String FilePath = Environment.getExternalStorageDirectory().toString() + "/lpr.key";
int nRet = api.Init(this, m_ROI[0], m_ROI[1], m_ROI[2], m_ROI[3], preHeight, preWidth, FilePath);
if (nRet != 0) {
bInitKernal = false;
Log.d("Status ", "相機開啟失敗");
} else {
bInitKernal = true;
}
}
private void onPreviewFrame(byte[] data) {
bIninKernal();
tackData = data;
Log.d("data length ", data.length + "");
resultStr = "";
if (!leaving && bInitKernal) {
byte[] result;
String res = "";
result = api.VideoRec(tackData, 1280, 400, 1);
try {
res = new String(result, "gb2312");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (res != null && !"".equals(res.trim())) {
resultStr = res.trim();
if (resultStr != "") {
leaving = true;
MediaActionSound sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
Log.d("Status ", "辨識成功");
Log.d("車牌號碼", resultStr);
Thread thread = new Thread(Image_update);
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent intent = new Intent(MainActivity2.this, MainActivity.class);
intent.putExtra("result", resultStr);
Log.d("result", resultStr);
setResult(1, intent);
finish();
}
} else {
Log.d("Status ", "未分辨車牌號碼,請重拍");
}
}
}
public void copyDataBase() throws IOException {
// Common common = new Common();
// 取得SK卡路徑/lpr.key
String dst = Environment.getExternalStorageDirectory().toString() + "/lpr.key";
File file = new File(dst);
if (!file.exists()) {
// file.createNewFile();
} else {
file.delete();
}
Log.d("File Name", file.toString());
try {
InputStream myInput = getAssets().open("lpr.key");
OutputStream myOutput = new FileOutputStream(dst);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch (Exception e) {
System.out.println("lpr.key" + "is not found");
}
}
private Runnable Image_update = new Runnable() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://0d9dccd7eac8.ngrok.io/")
.addConverterFactory(GsonConverterFactory.create())
.build();
MyAPIService myAPIService = retrofit.create(MyAPIService.class);
@Override
public void run() {
Log.d("Status ", "run");
Log.d("resultStr ", resultStr);
String url = "D:\Images\license_plate\";
String imgStr = bitmap2base64(toBitmap(image));
LicensePlate licensePlate = new LicensePlate();
licensePlate.setsPlate(resultStr);
licensePlate.setsPicPosition(url + resultStr);
licensePlate.setImgStr(imgStr);
Call<LicensePlate> call = myAPIService.uploadLicensePlate(licensePlate);
call.enqueue(new Callback<LicensePlate>() {
@Override
public void onResponse(Call<LicensePlate> call, Response<LicensePlate> response) {
if(response.isSuccessful()){
Log.d("Status ", "照片上傳成功");
}else{
Log.d("Status ", "照片上傳失敗");
Log.d("response code ", response.code() + "");
}
}
@Override
public void onFailure(Call<LicensePlate> call, Throwable t) {
Log.d("Status ", "onFailure");
Log.d("Message ", t.getMessage());
}
});
}
};
private String bitmap2base64(Bitmap bitmap){
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT).trim().replaceAll("\n", "").replaceAll("\r", "");
}
private Bitmap toBitmap(Image image) {
Image.Plane[] planes = image.getPlanes();
ByteBuffer yBuffer = planes[0].getBuffer();
ByteBuffer uBuffer = planes[1].getBuffer();
ByteBuffer vBuffer = planes[2].getBuffer();
int ySize = yBuffer.remaining();
int uSize = uBuffer.remaining();
int vSize = vBuffer.remaining();
byte[] nv21 = new byte[ySize + uSize + vSize];
//U and V are swapped
yBuffer.get(nv21, 0, ySize);
vBuffer.get(nv21, ySize, vSize);
uBuffer.get(nv21, ySize + vSize, uSize);
YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 75, out);
byte[] imageBytes = out.toByteArray();
return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
}
}
相机
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 隐藏标题
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int metricwidth = metric.widthPixels; // 屏幕宽度(像素)
int metricheight = metric.heightPixels; // 屏幕高度(像素)
try {
copyDataBase();
} catch (IOException e) {
e.printStackTrace();
}
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);// 竖屏
Configuration cf= this.getResources().getConfiguration(); //获取设置的配置信息
int noriention=cf.orientation;
requestWindowFeature(Window.FEATURE_NO_TITLE);// 隐藏标题
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
// // 屏幕常亮
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_lpr2);
findView();
}
private void findView() {
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
re_c = (RelativeLayout) findViewById(R.id.re_c);
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
width = metric.widthPixels; // 屏幕宽度(像素)
height = metric.heightPixels; // 屏幕高度(像素)
if(myView==null)
{
if (isFatty)
{
myView = new LPRfinderView2(LPR2Activity.this, width, height, isFatty);
}
else
{
myView = new LPRfinderView2(LPR2Activity.this, width, height);
}
re_c.addView(myView);
}
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(LPR2Activity.this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.setFocusable(true);
//surfaceView.invali.date();
}
public void copyDataBase() throws IOException {
// Common common = new Common();
// 取得SK卡路徑/lpr.key
String dst = Environment.getExternalStorageDirectory().toString() + "/lpr.key";
File file = new File(dst);
if (!file.exists()) {
// file.createNewFile();
} else {
file.delete();
}
Log.d("File Name", file.toString());
try {
InputStream myInput = getAssets().open("lpr.key");
OutputStream myOutput = new FileOutputStream(dst);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch (Exception e) {
System.out.println("lpr.key" + "is not found");
}
}
public void surfaceCreated(SurfaceHolder holder) {
if (mycamera == null) {
try {
mycamera = Camera.open();
} catch (Exception e) {
e.printStackTrace();
String mess = "打开摄像头失败";
Toast.makeText(getApplicationContext(), mess, Toast.LENGTH_LONG).show();
return;
}
}
if(mycamera!=null)
{
try {
mycamera.setPreviewDisplay(holder);
timer2 = new Timer();
if (timer == null)
{
timer = new TimerTask()
{
public void run()
{
if (mycamera != null)
{
try
{
mycamera.autoFocus(new AutoFocusCallback()
{
public void onAutoFocus(boolean success, Camera camera)
{
}
});
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
};
}
timer2.schedule(timer, 500, 2500);
initCamera();
//mycamera.startPreview();
//mycamera.autoFocus(null);
} catch (IOException e) {
e.printStackTrace();
}
}
if(api==null)
{
api= new LPR();
String FilePath =Environment.getExternalStorageDirectory().toString()+"/lpr.key";
int nRet = api.Init(this,m_ROI[0], m_ROI[1], m_ROI[2], m_ROI[3], preHeight, preWidth,FilePath);
if(nRet!=0)
{
Toast.makeText(getApplicationContext(), "啟動失敗,請調整時間", Toast.LENGTH_SHORT).show();
Log.d("nRet ", nRet + "");
bInitKernal =false;
}
else
{
bInitKernal=true;
}
}
if(alertDialog==null){
alertDialog = new AlertDialog.Builder(this).create();
alertDialoginfo = new AlertDialog.Builder(this).create();
}
}
@Override
public void surfaceChanged(final SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
try {
if (mycamera != null) {
mycamera.setPreviewCallback(null);
mycamera.stopPreview();
mycamera.release();
mycamera = null;
}
} catch (Exception e) {
}
if(bInitKernal){
bInitKernal=false;
api = null;
}
if(toast!=null){
toast.cancel();
toast = null;
}
if(timer2!=null){
timer2.cancel();
timer2=null;
}
if(alertDialog!=null)
{
alertDialog.dismiss();
alertDialog.cancel();
alertDialog=null;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
try {
if (mycamera != null) {
mycamera.setPreviewCallback(null);
mycamera.stopPreview();
mycamera.release();
mycamera = null;
}
} catch (Exception e) {
e.printStackTrace();
}
if(bInitKernal)
{
bInitKernal=false;
api = null;
}
finish();
if(toast!=null){
toast.cancel();
toast=null;
}
if(timer2!=null){
timer2.cancel();
timer2=null;
}
if(alertDialog!=null)
{
alertDialog.cancel();
alertDialog=null;
}
}
return super.onKeyDown(keyCode, event);
}
@TargetApi(14)
private void initCamera() {
Camera.Parameters parameters = mycamera.getParameters();
List<Camera.Size> list = parameters.getSupportedPreviewSizes();
preWidth = list.get(4).width;
preHeight = list.get(4).height;
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setPreviewSize(preWidth,preHeight);
if (!bROI) {
int l,t,r,b;
l = 100;
r = width-100;
int ntmpH =(r-l)*58/100;
t = (height-ntmpH)/2;
b = t+ntmpH;
double proportion = (double) width / (double) preHeight;
double hproportion=(double)height/(double) preWidth;
l = (int) (l /proportion);
t = (int) (t /hproportion);
r = (int) (r /proportion);
b = (int) (b / hproportion);
m_ROI[0]=l;
m_ROI[1]=t;
m_ROI[2]=r;
m_ROI[3]=b;
bROI = true;
}
if (parameters.getSupportedFocusModes().contains(
parameters.FOCUS_MODE_AUTO))
{
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);// 1连续对焦
}
mycamera.setPreviewCallback(LPR2Activity.this);
mycamera.setParameters(parameters);
mycamera.setDisplayOrientation(90); //一般機種
mycamera.startPreview();
}
public void onPreviewFrame(byte[] data, Camera camera) {
tackData = data;
Log.d("data length ", data.length + "");
ByteArrayInputStream bis = new ByteArrayInputStream(data);
resultStr = "";
if (!leaving&& bInitKernal ) {
Log.d("Status ", "開始判斷");
byte result[];//[] = new byte[10];
String res="";
result = api.VideoRec(tackData, preWidth, preHeight, 1);
Log.d("preWidth ", preWidth + "");
Log.d("preHeight", preHeight + "");
Log.d("width ", width + "");
Log.d("height", height + "");
try {
res = new String(result,"gb2312");
Log.d("try ", res);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
Log.d("Exception ", e.getMessage());
e.printStackTrace();
}
Log.d("res ", res);
if(res!=null&&!"".equals(res.trim()))
{
Camera.Parameters parameters = mycamera.getParameters();
resultStr =res.trim();
if (resultStr != "") {
leaving = true;
//拍照音效
MediaActionSound sound = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
}
Intent intent = new Intent();
intent.putExtra("strPltNo",resultStr);
setResult(2,intent);
finish();
}else{
Log.d("Status ", "未分配車牌號碼,請重拍");
}
}
}
}
@RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
public String pictureName() {
String str = "";
Time t = new Time();
t.setToNow(); // 取得系统时间。
int year = t.year;
int month = t.month + 1;
int date = t.monthDay;
int hour = t.hour; // 0-23
int minute = t.minute;
int second = t.second;
if (month < 10)
str = String.valueOf(year) + "0" + String.valueOf(month);
else {
str = String.valueOf(year) + String.valueOf(month);
}
if (date < 10)
str = str + "0" + String.valueOf(date + "_");
else {
str = str + String.valueOf(date + "_");
}
if (hour < 10)
str = str + "0" + String.valueOf(hour);
else {
str = str + String.valueOf(hour);
}
if (minute < 10)
str = str + "0" + String.valueOf(minute);
else {
str = str + String.valueOf(minute);
}
if (second < 10)
str = str + "0" + String.valueOf(second);
else {
str = str + String.valueOf(second);
}
return str;
}
public void Leave(View view) {
Intent intent = new Intent();
intent.putExtra("strPltNo","");
setResult(3,intent);
finish();
}
}
CameraX Log
Camera Log
关于图像分析分辨率,ImageAnalysis.Builder.setTargetResolution()
的文档指出:
The maximum available resolution that could be selected for an ImageAnalysis is limited to be under 1080p.
因此,将尺寸设置为 2560x800 不会如您所愿。在 return 中,CameraX 似乎正在选择与您请求的纵横比相同的最大 ImageAnalysis
分辨率 (2560/800 = 1280/400)。