You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
//----------------------------------------------------------------------------
// Copyright (C) 2004-2025 by EMGU Corporation. All rights reserved.
//----------------------------------------------------------------------------
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks;
using Emgu.CV; using Emgu.CV.Util; using Emgu.CV.CvEnum; using Emgu.CV.Structure; using Emgu.Util.TypeEnum;
using System.Runtime.InteropServices;
using Microsoft.Maui.Controls.PlatformConfiguration;
#if __MACCATALYST__
using AppKit; using CoreGraphics; #elif __IOS__
using UIKit; using CoreGraphics; using Microsoft.Maui.Controls.Compatibility.Platform.iOS; #elif __ANDROID__
using Android.Graphics; using Android.Views; using Android.Widget; using Android.Hardware.Lights; #elif WINDOWS
using Visibility = Microsoft.UI.Xaml.Visibility; using Microsoft.UI.Xaml.Media.Imaging; #endif
namespace Emgu.CV.Platform.Maui.UI { /// <summary>
/// A simple page with a button, message text and an image
/// </summary>
public class ButtonTextImagePage #if __IOS__
: Emgu.Util.AvCaptureSessionPage #elif __ANDROID__
: AndroidCameraPage #else
: ContentPage #endif
{ private Picker _picker = new Picker();
/// <summary>
/// Get the file picker
/// </summary>
public Picker Picker { get { return _picker; } }
private Microsoft.Maui.Controls.Button _topButton = new Microsoft.Maui.Controls.Button();
/// <summary>
/// Get the button at the top
/// </summary>
public Microsoft.Maui.Controls.Button TopButton { get { return _topButton; } }
private Label _messageLabel = new Label();
/// <summary>
/// Get the message label
/// </summary>
public Label MessageLabel { get { return _messageLabel; } }
private Editor _logEditor = new Editor(); /// <summary>
/// The log message editor
/// </summary>
public Editor LogEditor { get { return _logEditor; } }
private CvImageView _displayImage = new CvImageView();
/// <summary>
/// Get the displayed image
/// </summary>
public CvImageView DisplayImage { get { return _displayImage; } //set { _displayImage = value; }
}
/// <summary>
/// Set the image to be displayed
/// </summary>
/// <param name="image">The image to be displayed</param>
public virtual void SetImage(IInputArray image) { //No need to dispatch here, ImageView will handle the proper dispatch
this.DisplayImage.SetImage(image); }
private StackLayout _mainLayout = new StackLayout();
/// <summary>
/// Get the main layout
/// </summary>
public StackLayout MainLayout { get { return _mainLayout; } }
private Microsoft.Maui.Controls.Button[] _additionalButtons;
/// <summary>
/// Get the list of additional buttons
/// </summary>
public Microsoft.Maui.Controls.Button[] AdditionalButtons { get { return _additionalButtons; } }
/// <summary>
/// Create a simple page with a button, message label and image.
/// </summary>
/// <param name="additionalButtons">Additional buttons added below the standard button.</param>
public ButtonTextImagePage(Microsoft.Maui.Controls.Button[] additionalButtons = null) { var horizontalLayoutOptions = LayoutOptions.Center;
TopButton.Text = "Click me"; TopButton.IsEnabled = true; TopButton.HorizontalOptions = horizontalLayoutOptions;
MessageLabel.Text = ""; MessageLabel.HorizontalOptions = horizontalLayoutOptions;
//DisplayImage.HeightRequest = 100;
//DisplayImage.WidthRequest = 100;
//DisplayImage.MinimumHeightRequest = 10;
//StackLayout mainLayout = new StackLayout();
_mainLayout.Children.Add(Picker); Picker.IsVisible = false;
_mainLayout.Children.Add(TopButton); if (additionalButtons != null) { foreach (Microsoft.Maui.Controls.Button button in additionalButtons) { button.HorizontalOptions = horizontalLayoutOptions; _mainLayout.Children.Add(button); } }
_additionalButtons = additionalButtons;
_mainLayout.Children.Add(MessageLabel);
//MessageLabel.BackgroundColor = Color.AliceBlue;
//DisplayImage.BackgroundColor = Color.Aqua;
//_mainLayout.BackgroundColor = Color.Blue;
_mainLayout.Children.Add(DisplayImage); DisplayImage.BackgroundColor = Microsoft.Maui.Graphics.Color.FromRgb(1.0, 0.0, 0.0);
//_mainLayout.Children.Add(MessageLabel);
LogEditor.Text = ""; LogEditor.HorizontalOptions = LayoutOptions.Center; LogEditor.VerticalOptions = LayoutOptions.Center; LogEditor.FontSize = LogEditor.FontSize / 2; _mainLayout.Children.Add(LogEditor);
SetLog(null);
_mainLayout.Padding = new Thickness(10, 10, 10, 10);
this.Content = new Microsoft.Maui.Controls.ScrollView() { Content = _mainLayout }; }
/// <summary>
/// A flag that indicates if the file picker allow getting image from camera
/// </summary>
private bool? _hasCameraOption = null;
/// <summary>
/// Get the default camera option
/// </summary>
/// <returns>A flag that indicates if the file picker allow getting image from camera, will be used by HasCameraOption getter if no value is set.</returns>
protected virtual bool GetDefaultCameraOption() { return false; }
/// <summary>
/// A flag that indicates if the file picker allow getting image from camera
/// </summary>
public bool HasCameraOption { get { if (_hasCameraOption == null) { _hasCameraOption = GetDefaultCameraOption(); }
return _hasCameraOption.Value; } set { _hasCameraOption = value; } }
/// <summary>
/// Load the images and return them asynchronously
/// </summary>
/// <param name="imageNames">The name of the images</param>
/// <param name="labels">The labels of the images</param>
/// <returns>The images loaded</returns>
public virtual async Task<Mat[]> LoadImages(String[] imageNames, String[] labels = null) { Mat[] mats = new Mat[imageNames.Length];
SetMessage("Checking if camera option is available, please wait..."); //Run it once in case it need to check if camera is available, which could take a long time to run
await Task.Run(() => { bool cameraOption = this.HasCameraOption; }); SetMessage(null);
bool captureSupported;
if (Microsoft.Maui.Devices.DeviceInfo.Platform == DevicePlatform.WinUI || Microsoft.Maui.Devices.DeviceInfo.Platform == DevicePlatform.macOS) { //Pick image from camera is not implemented on WPF.
captureSupported = false; } else { captureSupported = MediaPicker.IsCaptureSupported; if (Microsoft.Maui.Devices.DeviceInfo.Platform == DevicePlatform.Android) { //Overwrite MediaPicker if there is no camera on this Android device.
if (!this.HasCameraOption) { captureSupported = false; } } }
for (int i = 0; i < mats.Length; i++) { String pickImgString = "Use Image from"; if (labels != null && labels.Length > i) pickImgString = labels[i];
String action; List<String> options = new List<string>(); options.Add("Default");
options.Add("Photo Library");
if (captureSupported) options.Add("Photo from Camera");
if (this.HasCameraOption) { if (Microsoft.Maui.Devices.DeviceInfo.Platform == DevicePlatform.Android) { if (captureSupported) { options.Add("Camera"); /* #if __ANDROID__
if (this.CameraBackend == AndroidCameraBackend.AndroidCamera2) { foreach (String cameraId in AndroidCameraManager.GetAvailableCameraIds()) { options.Add(String.Format("Camera {0}", cameraId)); } } else { options.Add("Camera"); } #else
options.Add("Camera"); #endif
*/ } } else if (Microsoft.Maui.Devices.DeviceInfo.Platform == DevicePlatform.iOS) { if (captureSupported) options.Add("Camera"); } else if (Microsoft.Maui.Devices.DeviceInfo.Platform == DevicePlatform.WinUI || Microsoft.Maui.Devices.DeviceInfo.Platform == DevicePlatform.macOS) { var openCVConfigDict = CvInvoke.ConfigDict; bool haveVideoio = (openCVConfigDict["HAVE_OPENCV_VIDEOIO"] != 0); if (haveVideoio) options.Add("Camera"); } }
if (options.Count == 1) { action = "Default"; } else { action = await DisplayActionSheet(pickImgString, "Cancel", null, options.ToArray()); if ( action == null //user clicked outside of action sheet
|| action.Equals("Cancel") // user cancel
) return null; }
if (action.Equals("Default")) { using (Stream stream = await FileSystem.OpenAppPackageFileAsync(imageNames[i])) using (MemoryStream ms = new MemoryStream()) { stream.CopyTo(ms); Mat m = new Mat(); CvInvoke.Imdecode(ms.ToArray(), ImreadModes.ColorBgr, m); mats[i] = m; }
} else if (action.Equals("Photo Library")) { /* if (Microsoft.Maui.Devices.DeviceInfo.Platform == DevicePlatform.WinUI) {
#if !(__MACCATALYST__ || __ANDROID__ || __IOS__ || NETFX_CORE)
Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog(); dialog.Multiselect = false; dialog.Title = "Select an Image File"; dialog.Filter = "Image | *.jpg;*.jpeg;*.png;*.bmp;*.gif | All Files | *"; if (dialog.ShowDialog() == false) return null; mats[i] = CvInvoke.Imread(dialog.FileName, ImreadModes.AnyColor); #endif
} else */ { FileResult fileResult = await FilePicker.PickAsync(PickOptions.Images); if (fileResult == null) //canceled
return null; using (Stream s = await fileResult.OpenReadAsync()) mats[i] = await ReadStream(s); } } else if (action.Equals("Photo from Camera")) { PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.Camera>(); if (status == PermissionStatus.Denied) { this.SetMessage("Please grant permission to use camera"); } else { var takePhotoResult = await MediaPicker.CapturePhotoAsync();
if (takePhotoResult == null) //canceled
return null; using (Stream stream = await takePhotoResult.OpenReadAsync()) mats[i] = await ReadStream(stream); } } else if (action.Equals("Camera")) { mats = new Mat[0]; #if __ANDROID__
String cameraIdCandidate = action.Replace("Camera ", ""); if (AndroidCameraManager.GetAvailableCameraIds().Contains(cameraIdCandidate)) { _preferredCameraId = cameraIdCandidate; } else { _preferredCameraId = null; } #endif
} }
return mats; }
private static async Task<Mat> ReadStream(Stream stream) { using (MemoryStream ms = new MemoryStream()) { await stream.CopyToAsync(ms); byte[] data = ms.ToArray(); Mat m = new Mat(); CvInvoke.Imdecode(data, ImreadModes.ColorBgr, m); return m; } }
/// <summary>
/// Get the message label UI
/// </summary>
/// <returns>The message label ui</returns>
public Label GetLabel() { //return null;
return this.MessageLabel; }
/// <summary>
/// Set the message to be displayed
/// </summary>
/// <param name="message">The message to be displayed</param>
public void SetMessage(String message) { this.Dispatcher.Dispatch( () => { Label label = GetLabel(); label.Text = message;
label.LineBreakMode = LineBreakMode.WordWrap; //label.WidthRequest = this.Width;
} ); }
private String _log = String.Empty;
/// <summary>
/// Clear the log
/// </summary>
public void ClearLog() { SetLog(String.Empty); }
/// <summary>
/// Set the log
/// </summary>
/// <param name="log">The log</param>
public void SetLog(String log) { _log = log; RenderLog(_log); }
/// <summary>
/// Append text to the log
/// </summary>
/// <param name="log">The text to be append to the log</param>
public void AppendLog(String log) { if (!String.IsNullOrEmpty(_log)) _log = log + _log; RenderLog(_log); }
/// <summary>
/// Render the log
/// </summary>
/// <param name="log">The log to be rendered</param>
private void RenderLog(String log) { this.Dispatcher.Dispatch( () => { if (String.IsNullOrEmpty(log)) { this.LogEditor.IsVisible = false; } else { this.LogEditor.IsVisible = true; }
this.LogEditor.Text = log; this.LogEditor.WidthRequest = this.Width; this.LogEditor.HeightRequest = 120;
//this.LogLabel.LineBreakMode = LineBreakMode.WordWrap;
this.LogEditor.Focus(); } ); }
/// <summary>
/// Get the main button
/// </summary>
/// <returns>The main button</returns>
public Microsoft.Maui.Controls.Button GetButton() { //return null;
return this.TopButton; }
}
}
|