I need some advice on how to use the camera in Xamarin.Forms.
Currently, NuGet Xam.Plugin.Media.
Media. With the following code, when you press a button from the UI, the camera starts up, takes a picture and displays the image on the screen.
private async void OnCameraTapped(object sender, EventArgs e)
{
var photo = await CaptureCamera();
Image.Source = ImageSource.FromStream() =>
{
return new MemoryStream(photo);
});
}
```
```
private async Task<byte[]> CaptureCamera()
{
await Plugin.Media.CrossMedia.Current. Initialize();
Initialize(); if (!Plugin.Media.CrossMedia.Current. IsCameraAvailable ||
!Plugin.Media.CrossMedia.Current. IsTakePhotoSupported)
{
return null;
}
var file = await Plugin.Media.CrossMedia. CrossMedia.
.TakePhotoAsync(
new Plugin.Media.Abstractions. StoreCameraMediaOptions
{
Directory = "Photo",
Name = DateTime.Now.ToString("yyyy_MMdd_HHHmm ") + "Photo.jpg",
});
if (file == null)
return null;
var bytes = new Queue<byte>();
using (var s = file.GetStream())
{
var length = s.Length;
int b;
while ((b = s.ReadByte()) ! = -1)
bytes.Enqueue((byte)b);
}
Dispose();
Dispose(); if (bytes == null) return null;
return bytes.ToArray();
}
However, this method uses Plugin.Media.CrossMedia, which means that the There are some restrictions. I would like to know how to get around those constraints.
Q) I need to press the shutter release and then press "OK" on the activated camera. I want to finish the process by just pressing the shutter release.
Q) The camera I started up defaults to out-camera. I want to take a picture of myself, so I want to start the in-camera as the default.
How can I get around the above two points?
My environment is as follows.
OS Windows 10 Home
IDE Visual Studio 2019 community
Xamarin.Form(.NET Standard 2.1)
Target Android 9.0(API 28)
Related
I have some code below that can take the current Image and displaying it whenever I click a PushSnap Button. How can I go about having it continuously capturing and displaying the updated image in an interval (say 100 ms)
private void PushSnap_Click(object sender, EventArgs e)
{
if (mycam == null)
{
MessageBox.Show("Internal Error: mycam is null");
return; // internal error
}
string text = "";
if (IsMyFormStatus_Opened())
{
if (!mydcam.buf_alloc(3))
{
MessageBox.Show("Frame allocation failed");
return;
}
}
// start acquisition
mycam.m_capmode = CAMCAP_START.SNAP; //one time capturing where Acquisition will start after m_nFrameCount frames
if (!mycam.cap_start())
{
return;
}
MyFormStatus_Acquiring();
MyThreadCapture_Start();
}
The Following MyThreadCapture_Start()
private void MyThreadCapture_Start()
{
m_threadCapture = new Thread(new ThreadStart(OnThreadCapture));
m_threadCapture.IsBackground = true;
m_threadCapture.Start();
}
and the following OnThreadCapture()
private void OnThreadCapture()
{
using (mycamwait = new MycamWait())
{
while (True)
{
CAMWAIT eventmask = CAMWAIT.CAPEVENT.FRAMEREADY | CAMWAIT.CAPEVENT.STOPPED;
DCAMWAIT eventhappened = DCAMWAIT.NONE;
if (mycamwait.start(eventmask, ref eventhappened))
{
if (eventhappened & CAMWAIT.CAPEVENT.FRAMEREADY)
{
int NewestFrame = 0;
int FrameCount = 0;
if (mycam.cap_transferinfo(ref NewestFrame, ref FrameCount))
{
MyUpdateImage(iNewestFrame);
}
}
if (eventhappened & CAMWAIT.CAPEVENT.STOPPED)
{
bContinue = false;
if (m_cap_stopping == false && mycam.m_capmode == CAMCAP_START.SNAP)
{
//cap_stop() happens automatically, therefore update the main dialog
//MySnapCaptureFinished();
}
}
}
}
}
Afterwards the Display is updated in the following way
private void UpdateDisplay()
{
Image oldImg = PicDisplay.Image;
if (m_bitmap != null)
{
// Show center of image
Int32 y0 = (m_image.height - PicDisplay.Height) / 2;
Int32 x0 = (m_image.width - PicDisplay.Width) / 2;
Rectangle rc = new Rectangle(x0, y0, PicDisplay.Width, PicDisplay.Height);
Bitmap bmp = new Bitmap(PicDisplay.Width, PicDisplay.Height, PixelFormat.Format24bppRgb);
using (var gr = Graphics.FromImage(bmp))
{
gr.DrawImage(m_bitmap, 0, 0, rc, GraphicsUnit.Pixel);
}
PicDisplay.Image = bmp;
PicDisplay.Refresh();
}
else
{
PicDisplay.Image = null;
}
if (oldImg != null)
oldImg.Dispose();
}
I would really recommend using Tasks instead of Threads. That should let you update your methods to take parameters and return results:
Image CaptureImage(); // I.e. similar code to OnThreadCapture
UpdateDisplay(Image);
And capture an image like:
public async void PushSnap_Click(){
...
try{
var image = await Task.Run(CaptureImage);
DisplayImage(image);
}
catch{
// Handle exceptions
}
That should let you simply rewrite your capture code to use a loop if you want live capture:
while(showLiveImagesBool){
var image = await Task.Run(CaptureImage);
DisplayImage(image);
}
The await-part should ensure the UI thread is not blocked while waiting for an image to be captured. If you do not want to show every image you might use a timer instead of a loop, just pick a timer that runs on the UI thread.
Keep in mind that showing live images will require a bit more performance, so you might need to optimize display and/or capture code. Ideally you should reuse image buffers when doing the capturing and displaying, otherwise you will allocate a fair amount of large objects that require a 2 gen GC to clean up.
I am having a problem with my gallery code, my Android does not recognize the right folder with the .jpg images on the line 20 and 30. It´s a lot different that a PC code cause of the disk details, if someone could help me, i will be a lot gratefull
public class Gallery : MonoBehaviour {
public List<Sprite> gallery = new List<Sprite>();
public Image displayImage;
public Button nextImg;
public Button prevImg;
public int i = 0;
void Start ()
{
// var Images = Directory.GetFiles("C:/Users/Bandeira/Downloads/Menu Start/Assets/Sprite/JPG/","*.jpg");
var Images = Directory.GetFiles("file:///" + "/unitypictures/","*.jpg");
Debug.Log(Images);
StartCoroutine(LoadImages(Images));
}
IEnumerator LoadImages(string[] Images)
{
foreach (var path in Images)
{
Debug.Log(path);
using (var uwr = UnityWebRequestTexture.GetTexture("file:///" + path))
// using (var uwr = UnityWebRequestTexture.GetTexture(path))
{
Debug.Log(path);
yield return uwr.SendWebRequest();
if (uwr.result != UnityWebRequest.Result.Success)
{
Debug.Log(uwr.error);
yield break;
}
var tex = DownloadHandlerTexture.GetContent(uwr);
var sprite = Sprite.Create(tex, new Rect(0f, 0f, tex.width, tex.height), new Vector2(0.5f, 0.5f), 50f, 0, SpriteMeshType.FullRect);
gallery.Add(sprite);
uwr.Dispose();
}
yield return null;
}
}
public void BtnNext (){
if(i + 1 < gallery.Count){
i++;
}
displayImage.sprite = gallery[i];
}
public void BtnPrev () {
if (i - 1 > 0){
i--;
}
displayImage.sprite = gallery[i];
}
}
Dude, I already told you yesterday.
You are using absolute paths, and they cannot work, because for each operating system they are different.
If you connect your Android phone to your computer, or install a file manager, you can see that there should be no folder called "UnityPictures", and even if there is you can't get there easily because I believe they are protected by the device.
The answer is always the same: you can use Persistent data path to save the images and resume them later.
For example you can save them in the Directory (Application.PersistentDataPath + "UnityPictures") and get them back from the same path.
So to be clear: you have to create the folder and insert those images, if you then want to download them.
Alternatively you can also download them from a server. So you could edit them, add more, or remove them without the need for updates, and it would be usable for all devices.
I need to save an image to disk that came from a web-cam between 5 and 10 seconds ago from when the "save" command comes in via serial port.
To get there, I have the webcam going into a pictureBox.Image (using opencv4), and then 2 Bitmap variables. Every 5 seconds a timer ticks, and Stored_bitmap_2 = Stored_bitmap_1, then Stored_bitmap_1 = (bitmap) pictureBox.Image.
When the right serial command comes in, I try to
Stored_image_2.Save("C:\Users\GreenWorld\Desktop\test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
and I get a run-time error of invalid parameter.
When I do the same thing in a stand-alone project with some buttons (inside the button-click event handler), it works every time.
When I do this inside the serialPort_DataReceived handler, I get all kinds of cross-thread errors. So, I moved the save attempt to its own subroutine, and that fixed that but now this.
I am by no means a professional programmer, I'm an engineer with a simple problem and I can usually write a little simplistic code to fix my immediate issue. Please go easy on me in the explanation :-)
Sample code:
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace Weld_picture
{
public partial class Form1 : Form
{
// Create class-level accessible variables
int Welding_camera_ID = 1;
VideoCapture capture;
Mat frame;
Bitmap image;
private Thread camera;
bool isCameraRunning = false;
string Serial_command = "";
Bitmap Stored_image_1;
Bitmap Stored_image_2;
bool Image_saved = false;
string Station_ID = "GWM-PWS-01";
string File_name = "";
private void CaptureCamera() // from someone else's sample code
{
camera = new Thread(new ThreadStart(CaptureCameraCallback));
camera.Start();
}
private void CaptureCameraCallback() // from someone else's sample code
{
frame = new Mat();
capture = new VideoCapture(Welding_camera_ID);
capture.Open(Welding_camera_ID);
if (capture.IsOpened())
{
while (isCameraRunning)
{
capture.Read(frame);
image = BitmapConverter.ToBitmap(frame);
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
pictureBox1.Image = image;
}
}
}
public Form1()
{
InitializeComponent();
SerialPort1.Open();
}
private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string dummy;
char CR = (char)0x0D;
while (SerialPort1.BytesToRead > 0)
{
Serial_command += (char)SerialPort1.ReadByte();
}
while (Serial_command.IndexOf(CR) > 0)
{
dummy = Serial_command.Substring(0, Serial_command.IndexOf(CR));
Serial_command = Serial_command.Substring(Serial_command.IndexOf(CR) + 1, (Serial_command.Length - (Serial_command.IndexOf(CR) + 1)));
Serial_command.Trim();
dummy.Trim();
proc_Process_serial_data(dummy);
}
}
//*************************************************************************************************************************************
/* the first timer is a 5-second interval. It's the "memory" function so that if/when the save-to-disk is triggered I can store the last-time-shutter-open image */
//*************************************************************************************************************************************
private void Timer_picture_interval_Tick(object sender, EventArgs e)
{
checkBox1.Checked = !checkBox1.Checked;
Timer_picture_interval.Stop();
Stored_image_2 = Stored_image_1;
Stored_image_1 = (Bitmap) pictureBox1.Image;
Timer_picture_interval.Start();
}
//*************************************************************************************************************************************
// the second timer is a 30-second interval. It's the way to turn capture off if the PLC/camera box somehow goes off-line
//*************************************************************************************************************************************
private void Timer_camera_powerdown_Tick(object sender, EventArgs e)
{
if (isCameraRunning)
capture.Release();
isCameraRunning = false;
Timer_picture_interval.Stop();
}
//*************************************************************************************************************************************
private void proc_Process_serial_data(string Serial_string)
{
if (Serial_string.IndexOf("Still here") > 0)
{
if (!isCameraRunning)
CaptureCamera();
isCameraRunning = true;
}
if (Serial_string.IndexOf("Sun's up") > 0)
{
Timer_picture_interval.Start();
Timer_camera_powerdown.Start();
}
if (Serial_string.IndexOf("It's dark") > 0)
{
if ((Stored_image_2 != null) && (!Image_saved)) // in case there's 2 subsequent requests to save the same thing (weld stutter)
{
File_name = "C:\\Users\\GreenWorld\\Desktop\\" + Station_ID + " D" + DateTime.Now.ToString("yyyy_MM_dd THH_mm_ss") + ".jpg";
Stored_image_2.Image.Save("C:\\Users\\GreenWorld\\Desktop\\test.bmp" , System.Drawing.Imaging.ImageFormat.Bmp );
Image_saved = true;
Timer_picture_interval.Stop();
}
Timer_camera_powerdown.Start();
}
}
}
}
You likely be able to fix the cros-threading error by simply calling your proc_Process_serial_data() method within an Invoke() call.
Change:
proc_Process_serial_data(dummy);
To:
this.Invoke((MethodInvoker)delegate ()
{
proc_Process_serial_data(dummy);
});
Also, these two lines aren't actually doing anything:
Serial_command.Trim();
dummy.Trim();
To Trim() the strings, you have capture the returned strings and re-assign them to the original variables:
Serial_command = Serial_command.Trim();
dummy = dummy.Trim();
I have a UWP app running on a surface pro device and I am trying to tell if a keyboard is attached to the device (this is the surface pro keyboard so attaches to the bottom, not usb) so that my application can go down different code paths.
Here is the list of things I have tried and their results:
1.
How to detect if the surface keyboard is attached?
KeyboardCapabilities keyboardCapabilities = new Windows.Devices.Input.KeyboardCapabilities();
return keyboardCapabilities.KeyboardPresent != 0 ? true : false;
But this always returns true on a surface pro device as specified here: Windows 8 WinRT KeyboardCapabilities.KeyboardPresent is always true
2. How to detect if the surface keyboard is attached?
Converted the Network watcher to c#
public bool KeyboardAttached { get; set; }
private void SetupKeyboardWatcher()
{
var watcher = Windows.Devices.Enumeration.DeviceInformation.CreateWatcher();
watcher.Added += Watcher_Added;
watcher.Updated += Watcher_Updated;
watcher.Removed += Watcher_Removed;
watcher.Start();
}
private void Watcher_Updated(Windows.Devices.Enumeration.DeviceWatcher sender, Windows.Devices.Enumeration.DeviceInformationUpdate args)
{
if (args.Id.IndexOf("{884b96c3-56ef-11d1-bc8c-00a0c91405dd}") != -1)
{
if (args.Properties.ContainsKey("System.Devices.InterfaceEnabled"))
{
// keyboard is connected
KeyboardAttached = true;
}
else
{
// keyboard disconnected
KeyboardAttached = false;
}
}
}
private void Watcher_Added(Windows.Devices.Enumeration.DeviceWatcher sender, Windows.Devices.Enumeration.DeviceInformation args)
{
if ((args.Id.IndexOf("{884b96c3-56ef-11d1-bc8c-00a0c91405dd}") != -1) && (args.Id.IndexOf("MSHW0007") == -1))
{
if (args.Properties.ContainsKey("System.Devices.InterfaceEnabled"))
{
// keyboard is connected
KeyboardAttached = true;
}
}
}
private void Watcher_Removed(Windows.Devices.Enumeration.DeviceWatcher sender, Windows.Devices.Enumeration.DeviceInformationUpdate args)
{
if (args.Id.IndexOf("{884b96c3-56ef-11d1-bc8c-00a0c91405dd}") != -1)
{
if (args.Properties.ContainsKey("System.Devices.InterfaceEnabled"))
{
// keyboard is connected
KeyboardAttached = true;
}
else
{
// keyboard disconnected
KeyboardAttached = false;
}
}
}
This returns keyboardAttached true when the onscreen keyboard shows up
3. How to detect if the surface keyboard is attached?
bool bIsDesktop = false;
var uiMode = UIViewSettings.GetForCurrentView().UserInteractionMode;
if (uiMode == Windows.UI.ViewManagement.UserInteractionMode.Mouse) // Typical of Desktop
bIsDesktop = true;
always returns true
Outside of my app the Windows OS acts differently depending on whether the keyboard is attached or not (it pops up a on screen keyboard) so there must be a way of doing it.
I'm not sure whether this link contains any information of relevance https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/keyboard-and-mouse-class-drivers
Is there a way of telling if a keyboard is attached to a surface pro device?
I am using MediaCapture class for camera view. But i have a problem that it supports only front camera of tablet, i want to switch between front and back camera by clicking a button.
How can i do it??
Sajid,
This example code from the Win8 Dev Center will show you how to enumerate through the camera devices connected to a current machine: http://code.msdn.microsoft.com/windowsapps/Media-Capture-Sample-adf87622
And here's another example which deals with DeviceEnumeration more specifically: http://code.msdn.microsoft.com/windowsapps/Device-Enumeration-Sample-a6e45169
Relevant code (from first link) :
private async void EnumerateWebcamsAsync()
{
try
{
ShowStatusMessage("Enumerating Webcams...");
m_devInfoCollection = null;
EnumedDeviceList2.Items.Clear();
m_devInfoCollection = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
if (m_devInfoCollection.Count == 0)
{
ShowStatusMessage("No WebCams found.");
}
else
{
for (int i = 0; i < m_devInfoCollection.Count; i++)
{
var devInfo = m_devInfoCollection[i];
EnumedDeviceList2.Items.Add(devInfo.Name);
}
EnumedDeviceList2.SelectedIndex = 0;
ShowStatusMessage("Enumerating Webcams completed successfully.");
btnStartDevice2.IsEnabled = true;
}
}
catch (Exception e)
{
ShowExceptionMessage(e);
}
}
edit: this code is taken from the AdvancedCapture.xaml.cs file from the first code sample I posted.