Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scanner improvements - added the logic from original zxing android project to set the best camera settings #789

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
226 changes: 218 additions & 8 deletions Source/ZXing.Net.Mobile.Android/CameraAccess/CameraAnalyzer.cs
@@ -1,19 +1,60 @@
using System;
/*
* Copyright 2018 ZXing/Redth - https://github.com/Redth/ZXing.Net.Mobile
*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*
* Edited by VK, Apacheta Corp 11/14/2018.
* http://www.apacheta.com/
*
*/

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Android.Views;
using ApxLabs.FastAndroidCamera;
using Android.Graphics;
using Android.Content;
using Android.Util;

namespace ZXing.Mobile.CameraAccess
{
public class CameraAnalyzer
{
/// <summary>
///START - Scanning Improvement, VK 11/14/2018
/// </summary>
private const int MIN_FRAME_WIDTH = 240;
private const int MIN_FRAME_HEIGHT = 240;
private const int MAX_FRAME_WIDTH = 640; // = 5/8 * 1920
private const int MAX_FRAME_HEIGHT = 480; // = 5/8 * 1080
/// <summary>
/// END - Scanning Improvement, VK 11/14/2018
/// </summary>
///

private readonly CameraController _cameraController;
private readonly CameraEventsListener _cameraEventListener;
private int _screenHeight = -1;
private int _screenWidth = -1;
private Task _processingTask;
private DateTime _lastPreviewAnalysis = DateTime.UtcNow;
private bool _wasScanned;
IScannerSessionHost _scannerHost;

private Rect framingRectInPreview;
private Rect framingRect;
private IWindowManager manager;
private bool _cameraSetup;

public CameraAnalyzer(SurfaceView surfaceView, IScannerSessionHost scannerHost)
Expand All @@ -22,6 +63,14 @@ public CameraAnalyzer(SurfaceView surfaceView, IScannerSessionHost scannerHost)
_cameraEventListener = new CameraEventsListener();
_cameraController = new CameraController(surfaceView, _cameraEventListener, scannerHost);
Torch = new Torch(_cameraController, surfaceView.Context);
try
{
manager = (surfaceView.Context as ZxingActivity)?.WindowManager;
}
catch(Exception ex)
{
Log.Debug(MobileBarcodeScanner.TAG, "Error occured while getting window manager : " + ex.ToString());
}
}

public event EventHandler<Result> BarcodeFound;
Expand Down Expand Up @@ -66,6 +115,15 @@ public void AutoFocus()
_cameraController.AutoFocus();
}

/// <summary>
///Scanning Improvement, VK 10/2018
///Removed this method for now.
/// </summary>
//public void LowLightMode(bool on)
//{
// _cameraController.LowLightMode(on);
//}

public void AutoFocus(int x, int y)
{
_cameraController.AutoFocus(x, y);
Expand All @@ -78,6 +136,14 @@ public void RefreshCamera()
_cameraController.RefreshCamera();
}

private bool Valid_ScreenResolution
{
get
{
return _screenHeight > 0 && _screenWidth > 0;
}
}

private bool CanAnalyzeFrame
{
get
Expand Down Expand Up @@ -114,14 +180,15 @@ private void HandleOnPreviewFrameReady(object sender, FastJavaByteArray fastArra
{
try
{
DecodeFrame(fastArray);
Log.Debug(MobileBarcodeScanner.TAG, "Preview Analyzing.");
DecodeFrame(fastArray);
} catch (Exception ex) {
Console.WriteLine(ex);
}
}).ContinueWith(task =>
{
if (task.IsFaulted)
Android.Util.Log.Debug(MobileBarcodeScanner.TAG, "DecodeFrame exception occurs");
Log.Debug(MobileBarcodeScanner.TAG, "DecodeFrame exception occurs");
}, TaskContinuationOptions.OnlyOnFaulted);
}

Expand Down Expand Up @@ -150,7 +217,28 @@ private void DecodeFrame(FastJavaByteArray fastArray)
ZXing.Result result = null;
var start = PerformanceCounter.Start();

LuminanceSource fast = new FastJavaByteArrayYUVLuminanceSource(fastArray, width, height, 0, 0, width, height); // _area.Left, _area.Top, _area.Width, _area.Height);
/// <summary>
///START - Scanning Improvement, VK Apacheta Corp 11/14/2018
///Added a new frame to get the center part of the captured image.
///To create a FastJavaByteArray from the cropped captured frame and use it to decode the barcode.
///To decrease the processing time drastically for higher resolution cameras.
/// </summary>
var frame_width = width * 3 / 5;
var frame_height = height * 3 / 5;
var frame_left = width * 1 / 5;
var frame_top = height * 1 / 5;

LuminanceSource fast = new FastJavaByteArrayYUVLuminanceSource(fastArray, width, height,
//framingRectPreview?.Width() ?? width,
// framingRectPreview?.Height() ?? height,
frame_left,
frame_top,
frame_width,
frame_height); // _area.Left, _area.Top, _area.Width, _area.Height);

/// <summary>
///END - Scanning Improvement, VK Apacheta Corp 11/14/2018
/// </summary>
if (rotate)
fast = fast.rotateCounterClockwise();

Expand All @@ -160,17 +248,139 @@ private void DecodeFrame(FastJavaByteArray fastArray)
fastArray = null;

PerformanceCounter.Stop(start,
"Decode Time: {0} ms (width: " + width + ", height: " + height + ", degrees: " + cDegrees + ", rotate: " +
rotate + ")");
$"width: {width}, height: {height}, frame_top :{frame_top}, frame_left: {frame_left}, frame_width: {frame_width}, frame_height: {frame_height}, degrees: {cDegrees}, rotate: {rotate}; " + "Decode Time: {0} ms");

if (result != null)
{
Android.Util.Log.Debug(MobileBarcodeScanner.TAG, "Barcode Found");
Log.Debug(MobileBarcodeScanner.TAG, "Barcode Found");

_wasScanned = true;
BarcodeFound?.Invoke(this, result);
return;
}
}


/// <summary>
///Scanning Improvement, VK 10/2018
/// </summary>
private Rect GetFramingRectInPreview()
{
if (framingRectInPreview == null)
{
//if (!Valid_ScreenResolution)
// GetScreenResolution();
var cameraParameters = _cameraController?.Camera?.GetParameters();
var width = cameraParameters.PreviewSize.Width;
var height = cameraParameters.PreviewSize.Height;
if (cameraParameters == null)//|| !Valid_ScreenResolution)
{
// Called early, before init even finished
return null;
}

var framingRect = GetFramingRect(width, height);
if (framingRect == null)
{
return null;
}

var rect = new Rect(framingRect);
//var cameraParameters = _cameraController?.Camera?.GetParameters();
//var width = cameraParameters.PreviewSize.Width;
//var height = cameraParameters.PreviewSize.Height;


//rect.Left = rect.Left * width / _screenWidth;
//rect.Right = rect.Right * width / _screenHeight;
//rect.Top = rect.Top * height / _screenWidth;
//rect.Bottom = rect.Bottom * height / _screenHeight;
framingRectInPreview = rect;
Log.Debug(MobileBarcodeScanner.TAG, $"preview resolution: w={width}; h={height}; _screenWidth ={_screenWidth}; _screenHeight={_screenHeight}; framingRect={framingRect?.ToString()}");
}

Log.Debug(MobileBarcodeScanner.TAG, $"Calculated preview framing rect: {framingRectInPreview?.FlattenToString()}");
return framingRectInPreview;
}

/// <summary>
///Scanning Improvement, VK 10/2018
/// </summary>
public Rect GetFramingRect(int _width, int _height)
{
if (framingRect == null)
{
if (_cameraController == null)
{
return null;
}

if (!(_width > 0 && _height > 0))//Valid_ScreenResolution)
{
// Called early, before init even finished
return null;
}

int width = findDesiredDimensionInRange(_width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
int height = findDesiredDimensionInRange(_height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);

int leftOffset = (_width - width) / 2;
int topOffset = (_height - height) / 2;
framingRect = new Rect(leftOffset, topOffset, width, height);
Log.Debug(MobileBarcodeScanner.TAG, $"Calculated framing rect: {framingRect?.FlattenToString()}; screenWidth: {_screenWidth}; screenHeight: {_screenHeight}");
}

return framingRect;
}

/// <summary>
///Scanning Improvement, VK 10/2018
/// </summary>
private void GetScreenResolution()
{
var screenResolution = new DisplayMetrics();
try
{
if(manager == null)
{
Log.Debug(MobileBarcodeScanner.TAG, $"Window manager is null.");
}

Display display = manager?.DefaultDisplay;
if (display == null)
{
Log.Debug(MobileBarcodeScanner.TAG, $"Default display is null.");
}
else
{

display?.GetMetrics(screenResolution);
_screenWidth = screenResolution.WidthPixels;
_screenHeight = screenResolution.HeightPixels;
}
Log.Debug(MobileBarcodeScanner.TAG, $"Screen Display Rect- Width = {_screenWidth}; Height = {_screenHeight} ");
}
catch (Exception ex)
{
Log.Debug(MobileBarcodeScanner.TAG, "Error occured while getting screen resolution : " + ex.ToString());
}
}

/// <summary>
///Scanning Improvement, VK 10/2018
/// </summary>
private int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax)
{
int dim = 5 * resolution / 8; // Target 5/8 of each dimension
if (dim < hardMin)
{
return hardMin;
}
if (dim > hardMax)
{
return hardMax;
}
return dim;
}
}
}
}