Image from Camera Preview using Customer Renderer is not clear - c#

I've followed this article and implemented a Customer Renderer that's used to display a preview video stream from the device's camera.
I intend to capture a frame from the live stream and feed it into Tesseract OCR in order to read a number printed on a ticket.
My problem is that the image from camera preview is almost always not focused. So it is useless for its intended purpose.
An identical question has been asked years ago here in SO, but the accepted answer is not at all helpful for me.
This is the code of OnElementChanged event of CameraPreviewRenderer:
void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)
{
CameraFragment newFragment = null;
if (e.OldElement != null)
{
e.OldElement.PropertyChanged -= OnElementPropertyChanged;
cameraFragment.Dispose();
}
if (e.NewElement != null)
{
this.EnsureId();
e.NewElement.PropertyChanged += OnElementPropertyChanged;
ElevationHelper.SetElevation(this, e.NewElement);
newFragment = new CameraFragment { Element = element };
}
FragmentManager.BeginTransaction()
.Replace(Id, cameraFragment = newFragment, "camera")
.Commit();
ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
}
This is a piece from class CameraFragment. Method RetrieveCameraDevice is the one that opens the camera (I think).
class CameraFragment : Fragment, TextureView.ISurfaceTextureListener
{
CameraDevice device;
CaptureRequest.Builder sessionBuilder;
CameraCaptureSession session;
CameraTemplate cameraTemplate;
CameraManager manager;
....
public async Task RetrieveCameraDevice(bool force = false)
{
if (Context == null || (!force && initTaskSource != null))
{
return;
}
if (device != null)
{
CloseDevice();
}
await RequestCameraPermissions();
if (!cameraPermissionsGranted)
{
return;
}
if (!captureSessionOpenCloseLock.TryAcquire(2500, TimeUnit.Milliseconds))
{
throw new RuntimeException("Timeout waiting to lock camera opening.");
}
IsBusy = true;
cameraId = GetCameraId();
if (string.IsNullOrEmpty(cameraId))
{
IsBusy = false;
captureSessionOpenCloseLock.Release();
Console.WriteLine("No camera found");
}
else
{
try
{
CameraCharacteristics characteristics = Manager.GetCameraCharacteristics(cameraId);
StreamConfigurationMap map = (StreamConfigurationMap)characteristics.Get(CameraCharacteristics.ScalerStreamConfigurationMap);
previewSize = ChooseOptimalSize(map.GetOutputSizes(Class.FromType(typeof(SurfaceTexture))),
texture.Width, texture.Height, GetMaxSize(map.GetOutputSizes((int)ImageFormatType.Jpeg)));
sensorOrientation = (int)characteristics.Get(CameraCharacteristics.SensorOrientation);
cameraType = (LensFacing)(int)characteristics.Get(CameraCharacteristics.LensFacing);
if (Resources.Configuration.Orientation == Android.Content.Res.Orientation.Landscape)
{
texture.SetAspectRatio(previewSize.Width, previewSize.Height);
}
else
{
texture.SetAspectRatio(previewSize.Height, previewSize.Width);
}
initTaskSource = new TaskCompletionSource<CameraDevice>();
Manager.OpenCamera(cameraId, new CameraStateListener
{
OnOpenedAction = device => initTaskSource?.TrySetResult(device),
OnDisconnectedAction = device =>
{
initTaskSource?.TrySetResult(null);
CloseDevice(device);
},
OnErrorAction = (device, error) =>
{
initTaskSource?.TrySetResult(device);
Console.WriteLine($"Camera device error: {error}");
CloseDevice(device);
},
OnClosedAction = device =>
{
initTaskSource?.TrySetResult(null);
CloseDevice(device);
}
}, backgroundHandler);
captureSessionOpenCloseLock.Release();
device = await initTaskSource.Task;
initTaskSource = null;
if (device != null)
{
await PrepareSession();
}
}
catch (Java.Lang.Exception ex)
{
Console.WriteLine("Failed to open camera.", ex);
Available = false;
}
finally
{
IsBusy = false;
}
}
}
I'm supposed to setup the "Focus Mode" in the Camera properties somewhere in this code. But I can't figure out a way to do this.

Related

How can I request permission from the user for autostart and for Battery saver(No restrictions) in Xamarin.Forms android?

I am creating an application for myself, and I need my service to work when the device is rebooted. I did it here is my code.
namespace Corporate_messenger.Droid.Broadcast
{
[BroadcastReceiver(Name = "com.companyname.corporate_messenger.BootReceiver", Enabled = true, Exported = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
public class BootReceiver : BroadcastReceiver
{
private void Start1(Context context)
{
Intent mycallIntent = new Intent(context, typeof(MainActivity));
mycallIntent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(mycallIntent);
}
public override void OnReceive(Context context, Intent intent)
{
try
{
var intentService = new Intent(context, typeof(NotoficationService));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
SpecialData.RestartResponse = true;
context.StartForegroundService(intentService);
}
else
{
context.StartService(intentService);
// Flag_On_Off_Service = true;
}
}
catch(Exception ex)
{
Log.Error("MyLog", ex.Message);
}
} // OnReceive
}
}
I also requested permissions to work with folders and microphone.
My cod - Permission
public async Task Permission()
{
var PermissionsStrorage_Write = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();
var PermissionsInternet = await Permissions.CheckStatusAsync<Permissions.NetworkState>();
var PermissionsStrorage_Read = await Permissions.CheckStatusAsync<Permissions.StorageRead>();
var PermissionsRecord = await Permissions.CheckStatusAsync<Permissions.Microphone>();
if (PermissionsInternet != PermissionStatus.Granted)
{
PermissionsInternet = await Permissions.RequestAsync<Permissions.NetworkState>();
}
if (PermissionsRecord != PermissionStatus.Granted)
{
PermissionsRecord = await Permissions.RequestAsync<Permissions.Microphone>();
}
if (PermissionsStrorage_Write != PermissionStatus.Granted && PermissionsStrorage_Read != PermissionStatus.Granted)
{
PermissionsStrorage_Write = await Permissions.RequestAsync<Permissions.StorageWrite>();
PermissionsStrorage_Read = await Permissions.RequestAsync<Permissions.StorageRead>();
}
if (PermissionsStrorage_Write != PermissionStatus.Granted && PermissionsStrorage_Read != PermissionStatus.Granted)
{
return;
}
}
Result code:
But I ran into a problem, which is that for my service to work correctly on some devices, two checkboxes are required. Here's a picture
Now I don't understand how to ask the user about these permissions so that he doesn't have to go into the settings himself. Perhaps the application could open this page on its own.Basically , this problem occurs on xiaomi phone. At the moment I am writing an application for android. But xamarin allows you to write code for iOS, so in the future I will also add such functions there.
here is the answer to this question
private void SetSetting()
{
// Manufacturer (Samsung)
var manufacturer = DeviceInfo.Manufacturer.ToLower();
switch (manufacturer)
{
case "xiaomi":
SetPermission("com.miui.powerkeeper", "com.miui.powerkeeper.ui.HiddenAppsConfigActivity");
break;
case "huawei":
SetPermission("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity");
break;
case "samsung":
if(Battery.EnergySaverStatus == EnergySaverStatus.On)
SetPermission("com.samsung.android.lool", "com.samsung.android.sm.battery.ui.BatteryActivity");
break;
}
}
private void SetPermission(string param1,string param2)
{
try
{
Intent intent = new Intent();
intent.SetComponent(new ComponentName(param1, param2));
// intent.SetComponent(new ComponentName("com.miui.securitycenter", "com.miui.appmanager.ApplicationsDetailsActivity"));
intent.PutExtra("package_name", PackageName);
StartActivity(intent);
}
catch (Exception anfe)
{
}
}
How to get into settings on other devices
How to start Power Manager of all android manufactures to enable background and push notification?
Only I just don't understand how to find out the status of the flag

How to implement multi threading on Text Adornment project VSIX

I am creating a VSIX project having TextAdornment features. Here when My CreateGeom() method executes, and try to run new Image{};, It throws exception The calling thread must be STA, because many UI components require this. I tried setting ApartmentState manually but no luck. Following is my code:
[STAThread]
internal async void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
{
string lang = getCurruntCodeLanguage();
if (lang.ToString() != "java" && lang.ToString() != "ts" && lang.ToString() != "js")
{
}
else
{
try
{
currentSnapshotText = this.view.TextBuffer.CurrentSnapshot.GetText();
this.currentSnapshotLinesList = this.view.TextBuffer.CurrentSnapshot.GetText().Split('\n');
foreach (string str in this.currentSnapshotLinesList.ToList<string>())
{
TextAdornment1.allLinesList.Add(str.Trim('\r'));
}
if (numberOfLinesBeforeEnter != this.currentSnapshotLinesList.Length)
{
boundstart = 0;
boundend = 0;
this.checkCountIfMarked = 1;
this.markthis.Clear();
if (this.image != null)
{
RemoveMarkedArea();
}
if (threadSendText != null)
{
if (threadSendText.IsAlive)
{
threadSendText.Abort();
}
}
var v = System.Threading.Thread.CurrentThread.GetApartmentState(); //returns 'STA'
threadSendText = new System.Threading.Thread(new ThreadStart(SndTextCall)); // Apartment State is 'Unknown'
threadSendText.SetApartmentState(ApartmentState.STA); // Apartment State is 'STA'
threadSendText.IsBackground = true;
threadSendText.Priority = ThreadPriority.Highest;
threadSendText.Start();
}
numberOfLinesBeforeEnter = this.currentSnapshotLinesList.Length;
}
catch (Exception exc)
{
//MessageBox.Show(exc.ToString());
}
}
}
There are other recursive methods also in SndTextCall(). All are working fine but when CreateGeom() method comes into execution, it throws an exception.
private void CreateGeom(SnapshotSpan span)
{
IWpfTextViewLineCollection textViewLines = this.view.TextViewLines;
this.geometry = textViewLines.GetMarkerGeometry(span);
if (this.geometry != null)
{
this.drawing = new GeometryDrawing(this.brush, this.pen, this.geometry);
this.drawing.Freeze();
var drawingImage = new DrawingImage(this.drawing);
drawingImage.Freeze();
image = new Image
{
Source = drawingImage,
}; // Here the exception comes
Canvas.SetLeft(image, this.geometry.Bounds.Left);
Canvas.SetTop(image, this.geometry.Bounds.Top);
this.drawingImageList.Add(image);
}
}
You can explicitly switch to the UI Thread using the VS Threading Rules or the explanations in the Cookbook for Visual Studio.
private void CreateGeom(SnapshotSpan span)
{
ThreadHelper.JoinableTaskFactory.Run(async delegate
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
// You're now on the UI thread.
// ... Create your image here
});
}

Task ends when getting GattService [C# UWP]

Using: Windows 10, C# .NET 2015 Community, UWP
Im trying to build a windows-universal-app that pairs my PC with a BLE device.
Whats already working is enumerating nearby devices, pair with a selected one and getting information like battery-level and firmware-revision.
The problem now is that when I try to get a custom service, my task ends because of an "System.Exception" at .GetGattService
System.Exception.Message: "Element not found. (Exception from HRESULT: 0x80070490)"
System.Exception.Stack : "at Windows.Devices.Bluetooth.BluetoothLEDevice.GetGattService(Guid serviceUuid)\r\n at SettingsCs.Settings.d__23.MoveNext()"
This is the code that's not working:
private async Task<SettingsReturn> writeSettingTransition(BluetoothLEDevice device, byte[] byteSettings)
{
//Check if device is available
if (device != null)
{
Guid SERVICE_CUSTOM = new Guid("7e0bc6be-8271-4f5a-a126-c24220e6250c");
GattDeviceService service = device.GetGattService(SERVICE_CUSTOM);
//Check if service is available
if (service == null)
{
return SettingsReturn.INIT_ERROR;
}
GattCharacteristic characteristic = service.GetCharacteristics(BLETestApp.CHAR_SETTINGS)[0];
//Check if characteristic is available
if (characteristic == null)
{
return SettingsReturn.INIT_ERROR;
}
var writer = new DataWriter();
writer.WriteBytes(byteSettings);
var buffer = writer.DetachBuffer();
await characteristic.WriteValueAsync(buffer);//********
bool success = characteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Write);
if (success == true)
{
// Take care of the 8 bit byte for the counter (max = 255 (unsigned))
if (TRANSACTION_ID > 250)
{
TRANSACTION_ID = 0;
}
else
{
// Count TANSACTION_ID one up
TRANSACTION_ID++;
}
return SettingsReturn.OK;
}
else
{
return SettingsReturn.WRITE_ERROR;
}
}
else
{
return SettingsReturn.INIT_ERROR;
}
}
I hope somenone can help me or tell me what I'm doing wrong.
I can't pinpoint the error you get, use the debugger to check if your characteristic has write permission.
I have changed your code in a way I write to my device successfully.
Also added a try catch block.
Here it is:
private async Task<SettingsReturn> writeSettingTransition(BluetoothLEDevice device, byte[] byteSettings)
{
bool success = false;
//Check if device is available
if (device != null)
{
Guid SERVICE_CUSTOM = new Guid("7e0bc6be-8271-4f5a-a126-c24220e6250c");
GattDeviceService service = device.GetGattService(SERVICE_CUSTOM);
//Check if service is available
if (service == null)
{
return SettingsReturn.INIT_ERROR;
}
GattCharacteristic characteristic = service.GetCharacteristics(BLETestApp.CHAR_SETTINGS)[0];
//Check if characteristic is available
if (characteristic == null)
{
return SettingsReturn.INIT_ERROR;
}
IBuffer writeBuffer = byteSettings.AsBuffer();// using Windows.Storage.Streams
try
{
// BT_Code: Writes the value from the buffer to the characteristic.
var result = await characteristic.WriteValueAsync(writeBuffer);
if (result == GattCommunicationStatus.Success)
{
// NotifyUser("Successfully wrote value to device" );
success = true;
}
else
{
// NotifyUser($"Write failed: {result}");
success = false;
}
}
catch (Exception ex) when ((uint)ex.HResult == 0x80650003 || (uint)ex.HResult == 0x80070005)
{
// E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED or E_ACCESSDENIED
// This usually happens when a device reports that it support writing, but it actually doesn't.
// NotifyUser(ex.Message, NotifyType.ErrorMessage);
}
if (success)
{
// Take care of the 8 bit byte for the counter (max = 255 (unsigned))
if (TRANSACTION_ID > 250)
{
TRANSACTION_ID = 0;
}
else
{
// Count TANSACTION_ID one up
TRANSACTION_ID++;
}
return SettingsReturn.OK;
}
else
{
return SettingsReturn.WRITE_ERROR;
}
}
else
{
return SettingsReturn.INIT_ERROR;
}
}
There can be typos and other mishaps, hope it helps.

LayoutSerializationCallback not be called

I'm using AvalonDock and I would serialize and deserialize my layout. But the callback (where I use the ContentId for create an instance of correct object) is not always called. For this reason the loaded not work correctly. I have tried to add one "try-catch", but not thrown exception.
This is my code:
` var layoutSerializer = new XmlLayoutSerializer(manager);
layoutSerializer.LayoutSerializationCallback += (s, e) =>
{
MyClass item;
if (items.TryGetValue(e.Model.ContentId, out item))
{
e.Content = item;
var tool = item as IMyClassToolApp;
var anchorable = e.Model as LayoutAnchorable;
var document = item as IMyClassDocumentApp;
var layoutDocument = e.Model as LayoutDocument;
if (tool != null && anchorable != null)
{
addToolCallback(tool);
tool.IsVisible = anchorable.IsVisible;
tool.IsSelected = e.Model.IsSelected;
return;
}
if (document != null && layoutDocument != null)
{
addDocumentCallback(document);
// Nasty hack to get around issue that occurs if documents are loaded from state,
// and more documents are opened programmatically.
layoutDocument.GetType().GetProperty("IsLastFocusedDocument").SetValue(layoutDocument, false, null);
document.IsVisible = true;
document.IsSelected = layoutDocument.IsSelected;
return;
}
}
e.Cancel = true;
};
try
{
layoutSerializer.Deserialize(stream);
}
catch
{
return false;
}`
Thank you for your help!
Are you sure your stream is O.K? If for example configuration file does not exist LayoutSerializationCallback method will not be called.
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
try
{
MainWindow.logger.Debug("Entering: {0}", "MainWindow_Loaded");
string filePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
#"Jofta\Analyzer\configs\AvalonDock.config");
if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
{
XmlLayoutSerializer serializer = new XmlLayoutSerializer(this.dockingManager);
serializer.LayoutSerializationCallback += this.Serializer_LayoutSerializationCallback;
serializer.Deserialize(filePath);
}
MainWindow.logger.Debug("Exiting: {0}", "MainWindow_Loaded");
}
catch (Exception ex)
{
MainWindow.logger.Error("Exception in: {0}", "MainWindow_Loaded");
MainWindow.logger.Error("Message: {0}", ex.Message);
}
}
private void Serializer_LayoutSerializationCallback(object sender, LayoutSerializationCallbackEventArgs e)
{
try
{
MainWindow.logger.Debug("Entering: {0}", "serializer_LayoutSerializationCallback");
if (e.Model.ContentId == ObjectExplorerViewModel.AnchorableContentId)
{
e.Content = Workspace.Instance.ObjectExplorer;
return;
}
// ...
// ...
MainWindow.logger.Debug("Exiting: {0}", "serializer_LayoutSerializationCallback");
}
catch (Exception ex)
{
MainWindow.logger.Error("Exception in: {0}", "serializer_LayoutSerializationCallback");
MainWindow.logger.Error("Message: {0}", ex.Message);
}
}

Turn Flash On/Off

OK, My issue is quite simple.
I've managed to turn the flash On (and keep it On).
However, I'm still not sure how to turn it off (lol).
Here's my code :
var sensorLocation = CameraSensorLocation.Back;
try
{
// get the AudioViceoCaptureDevice
var avDevice = await AudioVideoCaptureDevice.OpenAsync(sensorLocation,
AudioVideoCaptureDevice.GetAvailableCaptureResolutions(sensorLocation).First());
// turn flashlight on
var supportedCameraModes = AudioVideoCaptureDevice
.GetSupportedPropertyValues(sensorLocation, KnownCameraAudioVideoProperties.VideoTorchMode);
if (supportedCameraModes.ToList().Contains((UInt32)VideoTorchMode.On))
{
avDevice.SetProperty(KnownCameraAudioVideoProperties.VideoTorchMode, VideoTorchMode.On);
// set flash power to maxinum
avDevice.SetProperty(KnownCameraAudioVideoProperties.VideoTorchPower,
AudioVideoCaptureDevice.GetSupportedPropertyRange(sensorLocation, KnownCameraAudioVideoProperties.VideoTorchPower).Max);
}
else
{
turnWhiteScreen(true);
}
}
catch (Exception ex)
{
// Flashlight isn't supported on this device, instead show a White Screen as the flash light
turnWhiteScreen(true);
}
Any ideas?
P.S.
I imagined that converting .ons to .offs could have worked, but it doesn't.
This has been tested on a HTC 8S and Lumia 820.
It looks like you can't retrieve the acquisition device twice (I'm not sure why), so you should store it in a property:
protected AudioVideoCaptureDevice Device { get; set; }
private async void ButtonTurnOn_Click(object sender, RoutedEventArgs e)
{
var sensorLocation = CameraSensorLocation.Back;
try
{
if (this.Device == null)
{
// get the AudioViceoCaptureDevice
this.Device = await AudioVideoCaptureDevice.OpenAsync(sensorLocation,
AudioVideoCaptureDevice.GetAvailableCaptureResolutions(sensorLocation).First());
}
// turn flashlight on
var supportedCameraModes = AudioVideoCaptureDevice
.GetSupportedPropertyValues(sensorLocation, KnownCameraAudioVideoProperties.VideoTorchMode);
if (supportedCameraModes.ToList().Contains((UInt32)VideoTorchMode.On))
{
this.Device.SetProperty(KnownCameraAudioVideoProperties.VideoTorchMode, VideoTorchMode.On);
// set flash power to maxinum
this.Device.SetProperty(KnownCameraAudioVideoProperties.VideoTorchPower,
AudioVideoCaptureDevice.GetSupportedPropertyRange(sensorLocation, KnownCameraAudioVideoProperties.VideoTorchPower).Max);
}
else
{
turnWhiteScreen(true);
}
}
catch (Exception ex)
{
// Flashlight isn't supported on this device, instead show a White Screen as the flash light
turnWhiteScreen(true);
}
}
Then, to turn it off:
private void ButtonTurnOff_Click(object sender, RoutedEventArgs e)
{
var sensorLocation = CameraSensorLocation.Back;
try
{
// turn flashlight on
var supportedCameraModes = AudioVideoCaptureDevice
.GetSupportedPropertyValues(sensorLocation, KnownCameraAudioVideoProperties.VideoTorchMode);
if (this.Device != null && supportedCameraModes.ToList().Contains((UInt32)VideoTorchMode.Off))
{
this.Device.SetProperty(KnownCameraAudioVideoProperties.VideoTorchMode, VideoTorchMode.Off);
}
else
{
turnWhiteScreen(false);
}
}
catch (Exception ex)
{
// Flashlight isn't supported on this device, instead show a White Screen as the flash light
turnWhiteScreen(false);
}
}
Try this one
private static VideoTorchMode _videoTorchMode = VideoTorchMode.Off;
private AudioVideoCaptureDevice _videoRecordingDevice;
Check torch is exist in device.
private async void CheckTorch() {
if(AudioVideoCaptureDevice.AvailableSensorLocations.Contains(CameraSensorLocation.Back) &&
AudioVideoCaptureDevice.GetSupportedPropertyValues(CameraSensorLocation.Back, KnownCameraAudioVideoProperties.VideoTorchMode).ToList().Contains((UInt32)VideoTorchMode.On)) {
var temp = AudioVideoCaptureDevice.GetAvailableCaptureResolutions(CameraSensorLocation.Back)[0];
var resolution = new Windows.Foundation.Size(temp .Width, temp .Height);
_videoRecordingDevice = await AudioVideoCaptureDevice.OpenAsync(CameraSensorLocation.Back, resolution);
}
else
MessageBox.Show("Your device does not support torch");
}
To change torch state
private void SetTorchMode(){
try {
if (BackgroundHandler.Instance.IsBackTorchExist) {
if (_videoTorchMode == VideoTorchMode.Off) {
_videoRecordingDevice.SetProperty(KnownCameraAudioVideoProperties.VideoTorchMode, VideoTorchMode.On);
_videoTorchMode = VideoTorchMode.On;
}
else {
_videoRecordingDevice.SetProperty(KnownCameraAudioVideoProperties.VideoTorchMode, VideoTorchMode.Off);
_videoTorchMode = VideoTorchMode.Off;
}
}
}
catch (Exception ex){ }
}

Categories