- Home /
WebCamTexture, get correct resolution and RATIO.
After searching for a while, I've seen different solutions to get this right. Most of them suggesting first instantiating the WebCamTexture to a high resoulution. This does not work at all.
How do you, correctly, get the actual camera aspect ratio and the actual pixels??
Note
at this point 2016 the only real solution is to use "NatCam" on the asset store.
you can avoid 4-10 weeks of work, it is the only realistic solution until Unity fix their shit
Answer by Fattie · Feb 29, 2016 at 12:16 AM
note
Thes days just use
NatCam
on the asset store. It saves 4-10 man-weeks of work.
Jonny Roy's answer is partially correct. This is a huge know bug / disaster in Unity. For years they have not fixed, mentioned or addressed the issue.
(1) The solution is this: the reported size only becomes correct after some time (1/2 sec or so).
(2) Before that the width is reported as a small number under 100. it sounds bizarre but you have to watch each frame for a number over 100. It works 100% reliably.
Note these days you would never use a WebCamTexture on anything but UI, here is a post to save some typing: http://answers.unity3d.com/questions/909967/getting-a-web-cam-to-play-on-ui-texture-image.html
And nowm how to spin the image!
Here is the state of the art, 2016, for fixing the ratio, spin, and mirror of WebCamTexture. Works on both Android and iOS:
private void Update()
{
if ( wct.width < 100 )
{
Debug.Log("Still waiting another frame for correct info...");
return;
}
// change as user rotates iPhone or Android:
int cwNeeded = wct.videoRotationAngle;
// Unity helpfully returns the _clockwise_ twist needed
// guess nobody at Unity noticed their product works in counterclockwise:
int ccwNeeded = -cwNeeded;
// IF the image needs to be mirrored, it seems that it
// ALSO needs to be spun. Strange: but true.
if ( wct.videoVerticallyMirrored ) ccwNeeded += 180;
// you'll be using a UI RawImage, so simply spin the RectTransform
rawImageRT.localEulerAngles = new Vector3(0f,0f,ccwNeeded);
float videoRatio = (float)wct.width/(float)wct.height;
// you'll be using an AspectRatioFitter on the Image, so simply set it
rawImageARF.aspectRatio = videoRatio;
// alert, the ONLY way to mirror a RAW image, is, the uvRect.
// changing the scale is completely broken.
if ( wct.videoVerticallyMirrored )
rawImage.uvRect = new Rect(1,0,-1,1); // means flip on vertical axis
else
rawImage.uvRect = new Rect(0,0,1,1); // means no flip
// devText.text =
// videoRotationAngle+"/"+ratio+"/"+wct.videoVerticallyMirrored;
}
Hope it saves someone a LOT of time.
However see George's critical notes in the other answer!!!!!!!
Thanks for this answer. I have a question about:
if ( wct.videoVertically$$anonymous$$irrored )
rawImage.uvRect = new Rect(1,0,-1,1); // means flip on vertical axis
Why Rect(1,0,-1,1), i.e. horizontal flip and not Rect(0, 1, 1, -1), i.e. vertical flip?
Shouldn't a vertical flip be required for a "videoVertically$$anonymous$$irrored" WebCamTexture?
Also, I can't seem to be able to mirror the RawImage for front-facing cameras without making it also flip vertically for some reason...
Hi George - I m absolutely not sure, and you may be perfectly correct about what Unity means ........... (also, their doco is often plain wrong, so I don't know) ...
A great point. Let me know what you find out from experimentation!!
Thanks for this.
This has been really useful for me too, so thanks, however I have something to add. I was trying to get the camera image as large on the screen as possible. However it was appearing quite small. It turned out that in my case the code was having to rotate the image 90 degrees, which was confusing the aspect ratio fitter, so that the final image I saw on screen was only as tall as my screen was wide.
I'm solving this by checking whether the imaging is being rotated and scaling the object containing my raw image by the aspect ratio if it is.
In your code it would look something like this;
if (ccwNeeded != 0 &&
ccwNeeded % 90)
{
parentTransform.localScale = new Vector3(videoRatio, videoRatio, 1);
}
else
{
parentTransform.localScale = new Vector3(1, 1, 1);
}
I don't know if there's something I missed which caused this but it seems to fix it for so I though I would mention it in case anyone runs into the same issue.
NatCam's developer here. I often wish that Unity would offer a way to pay for assets by implementing a plan. We would have jumped on creating a lite version of NatCam but the nature of the API does not permit it--it's either all or nothing. You could email me at olokobayusuf@gmail.com and we'll see if we can work something out for you. I honestly don't want the price to be a difficulty for developers, but I have specific instructions when it comes to pricing.
Answer by georgehbr · Mar 15, 2016 at 01:31 PM
Update:
Here's the full script I'm using for displaying the device camera feed on a UI image with correct orientation and ratio, front and back cameras, and mirroring the front camera to make it look more natural, along with a screenshot of my hierarchy and RawImage game object. It's based on this answer by @Fattie, this other answer by Max Bot, reading the Unity documentation on WebCamTexture and WebCamDevice, and trial and error on a Nexus 5 running Android 6 and an iPhone 5S running iOS 9.
Hierarchy:
DeviceCameraController.cs:
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
using System.Collections;
public class DeviceCameraController : MonoBehaviour
{
public RawImage image;
public RectTransform imageParent;
public AspectRatioFitter imageFitter;
// Device cameras
WebCamDevice frontCameraDevice;
WebCamDevice backCameraDevice;
WebCamDevice activeCameraDevice;
WebCamTexture frontCameraTexture;
WebCamTexture backCameraTexture;
WebCamTexture activeCameraTexture;
// Image rotation
Vector3 rotationVector = new Vector3(0f, 0f, 0f);
// Image uvRect
Rect defaultRect = new Rect(0f, 0f, 1f, 1f);
Rect fixedRect = new Rect(0f, 1f, 1f, -1f);
// Image Parent's scale
Vector3 defaultScale = new Vector3(1f, 1f, 1f);
Vector3 fixedScale = new Vector3(-1f, 1f, 1f);
void Start()
{
// Check for device cameras
if (WebCamTexture.devices.Length == 0)
{
Debug.Log("No devices cameras found");
return;
}
// Get the device's cameras and create WebCamTextures with them
frontCameraDevice = WebCamTexture.devices.Last();
backCameraDevice = WebCamTexture.devices.First();
frontCameraTexture = new WebCamTexture(frontCameraDevice.name);
backCameraTexture = new WebCamTexture(backCameraDevice.name);
// Set camera filter modes for a smoother looking image
frontCameraTexture.filterMode = FilterMode.Trilinear;
backCameraTexture.filterMode = FilterMode.Trilinear;
// Set the camera to use by default
SetActiveCamera(frontCameraTexture);
}
// Set the device camera to use and start it
public void SetActiveCamera(WebCamTexture cameraToUse)
{
if (activeCameraTexture != null)
{
activeCameraTexture.Stop();
}
activeCameraTexture = cameraToUse;
activeCameraDevice = WebCamTexture.devices.FirstOrDefault(device =>
device.name == cameraToUse.deviceName);
image.texture = activeCameraTexture;
image.material.mainTexture = activeCameraTexture;
activeCameraTexture.Play();
}
// Switch between the device's front and back camera
public void SwitchCamera()
{
SetActiveCamera(activeCameraTexture.Equals(frontCameraTexture) ?
backCameraTexture : frontCameraTexture);
}
// Make adjustments to image every frame to be safe, since Unity isn't
// guaranteed to report correct data as soon as device camera is started
void Update()
{
// Skip making adjustment for incorrect camera data
if (activeCameraTexture.width < 100)
{
Debug.Log("Still waiting another frame for correct info...");
return;
}
// Rotate image to show correct orientation
rotationVector.z = -activeCameraTexture.videoRotationAngle;
image.rectTransform.localEulerAngles = rotationVector;
// Set AspectRatioFitter's ratio
float videoRatio =
(float)activeCameraTexture.width / (float)activeCameraTexture.height;
imageFitter.aspectRatio = videoRatio;
// Unflip if vertically flipped
image.uvRect =
activeCameraTexture.videoVerticallyMirrored ? fixedRect : defaultRect;
// Mirror front-facing camera's image horizontally to look more natural
imageParent.localScale =
activeCameraDevice.isFrontFacing ? fixedScale : defaultScale;
}
}
Comments on Fattie's Answer:
So I'm pretty sure at this point that "verticallyMirrored" means that a rotation about the horizontal axis is needed. So I've modified the code in Fattie's answer to:
int ccwNeeded = -wct.videoRotationAngle;
rawImageRT.localEulerAngles = new Vector3(0f,0f,ccwNeeded);
float videoRatio = (float)wct.width/(float)wct.height;
rawImageARF.aspectRatio = videoRatio;
if ( wct.videoVerticallyMirrored )
rawImage.uvRect = new Rect(0,1,1,-1); // flip on HORIZONTAL axis
else
rawImage.uvRect = new Rect(0,0,1,1); // no flip
i.e. I removed "if ( wct.videoVerticallyMirrored ) ccwNeeded += 180;" and changed the flipped uvRect values. I'll post a new answer here or somewhere on this site with my full script once I iron it out which includes using both front and back cameras and mirroring the front camera's texture to make it more natural.
I converted your comment to an answer since it is so important, good one
I also sent 100 "reward points" ! :) Am waiting with bated breath to see your further info, be sure to post it here please!!!! Cheers...
That's really helpful!
I don't suppose you could share what's in the aspect filter?
Thank , that totaly worked. but i have litte problem about resolution . after i build in my phone 13 $$anonymous$$P camera the image saved in my phoe blurry :( .
How to get the best resolution and not blurry
really suggest you just get NatCam .... save you weeks of time!
suggest you email the NatCam dudes they are very helpful. Even if you are not a customer they will solve your problem. it is very "specialized" field, you have to work on it all day every day.
enjoy!
Answer by Lanre · Mar 17, 2016 at 06:01 PM
Have you tried NatCam? It works wonders and has a lot more features.
Fantastic, I'm glad you told us about it. I will test it.
I sent you 50 "reward points" for bringing this to our attention :)
I would like to see a video of that plugin working, that would be reassuring. Does it replace WebCamTexture
?
Hi Fattie. It does! I am the publisher and my email address is olokobayusuf@gmail.com. Sorry for the inconvenience.
The email is in "Support Email" right next to "Publisher Website". Will be more clear when I upload package v1.1
Answer by Zoophish · May 24, 2017 at 07:39 AM
Unity 5.6.1 Release Notes [Extract]:
Android: Fixed WebCamTexture crash with denied permissions. (877837)
Android: Webcam - Fixed the wrong orientation returned on first frames. (875247)
Hope this solves a small issue faced here.
Answer by highpockets · Nov 18, 2020 at 12:11 PM
Hey I was having good fun with this on iOS, but I resolved it in the end with something pretty short and sweet.
I still needed to wait for the WebCamTexture.width
to be more than 100 before adding it to the raw image texture/material and then I used SetNativeSize()
on the raw texture. Here is my code for initialization:
private IEnumerator WaitForWebCamAndInitialize( WebCamTexture _webCamTexture )
{
while( _webCamTexture.width < 100 )
yield return null;
_isWebCamSet = true;
_rawCamImage.texture = _webCamTexture;
_rawCamImage.material.mainTexture = _webCamTexture;
_rawCamImage.SetNativeSize();
StartCoroutine( FadeToCameraView() );
}
FadeToCameraView()
does as it suggests.
I also had to rotate the rect transform negative 90 on the z axis because the app runs in portrait mode only and the raw data from the iOS camera seems to be aligned with landscape mode. Now everything works like a charm on iOS, but testing on the iMac shows the image rotated by the negative 90 I gave it.
Hope that helps someone
This was needed for me, we had to first create the webcamtexture and use .Play on it before calling this. It was easier to use in and Ienumerator Start sequence to wait until the width was ready.
You could even make this slightly more compact by replacing this:
while( _webCamTexture.width < 100 )
yield return null;
with this:
yield return new WaitWhile(() => _webCamTexture.width < 100);
Your answer
Follow this Question
Related Questions
WebCamTexture, correct resolution and RATIO.And FPS 1 Answer
how to get 4:3 non cropped WebCamTexture in iOS 0 Answers
Unwanted delay with WebCamTexture on Phone 0 Answers
iOS WebCamTexture Blur Get/Set Pixels 0 Answers
Lock aspect ratio for iOS device 0 Answers