- Home /
How Can I Get the Device Camera Aspect Ratio?
I've been using the WebCamTexture class to implement device camera views on mobile devices (both iPhones and Androids). However, I've noticed that the aspect ratio of the camera on a device does not necessarily match the aspect ratio of the screen (esp. on the wide-screen Androids). I can force the aspect to be 4:3 (which suits MOST cases), but what if the device's camera uses something different?
I can't find any information in WebCamTexture or WebCamDevice to help get the appropriate aspect ratio. Can anyone help?
Answer by Fattie · Apr 16, 2014 at 10:54 AM
Here's the state of the art solution for 2016:
http://answers.unity3d.com/questions/909967/getting-a-web-cam-to-play-on-ui-texture-image.html
Hope it helps someone!
Thanks, Fattie! $$anonymous$$ost helpful.
It's too bad this seems to be a very low-priority for Unity. It's really useful for augmented reality applications, but Unity Tech seems to favour AAA game features.
Answer by Jason-RT-Bond · Feb 08, 2013 at 11:41 PM
This is quite belated, but I was prepping a test project to submit with a bug report, and discovered a solution.
Following what rutter suggested, you can indeed request a high resolution and framerate, and will generally get the best available (e.g ask for 1080p at 60fps and you'll get 720p at 30fps). This is NOT ideal by any means, but it gets you something. The problem then is with the "16x16" size Unity seems to report for the camera texture, as mentioned by BTamas. This is what Unity gives back on an iPad even with the latest version (4.0.1) after requesting Play on the camera texture. With these (incorrect) numbers it seems impossible to set the dimensions correctly.
HOWEVER, the cause of this seems to be that starting the camera is asynchronous. By constantly checking them after starting the camera, I found that I would soon get correct values across all my devices (iPads 2, 3 and 4, iPhone 5 and Samsung Galaxy wifi 5.0 all worked). There doesn't seem to be any way of knowing when these values will be correct, though, so you must monitor them in a script, rather than simply setting the size of your plane/surface/shader at one particular moment.
The solution in brief:
Set the desired resolution to be very high, as rutter suggested.
After asking the camera to start, monitor the size of the texture for a while (keep checking the width and height in the Update method of a script). It should be set to the correct size eventually. (Possibly several frames?)
Note: This solution will only allow you to get the highest available resolution. It would still be better to be able to read a set of supported resolutions ahead of time so you can choose a more appropriate one.
Hey, Thanks for explaining it, but I'm still a little lost. I've followed all the suggestions but i am still having issues. We have a RawImage 480x480 - here is the code I'm using as suggested by the above answer:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class ShowCameraScript : $$anonymous$$onoBehaviour {
public RawImage rawimage;
private WebCamTexture webcamTexture;
void Start ()
{
WebCamDevice[] devices = WebCamTexture.devices;
webcamTexture = new WebCamTexture(devices[0].name,480,480,30);
rawimage.texture = webcamTexture;
rawimage.material.mainTexture = webcamTexture;
webcamTexture.Play();
}
void Update()
{
if ( webcamTexture.width < 100 )
{
Debug.Log("Still waiting another frame for correct info...");
Debug.Log("width is: " + webcamTexture.width.ToString());
return;
}
// change as user rotates iPhone or Android:
int cwNeeded = webcamTexture.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 ( webcamTexture.videoVertically$$anonymous$$irrored ) ccwNeeded += 180;
// you'll be using a UI RawImage, so simply spin the RectTransform
rawimage.rectTransform.localEulerAngles = new Vector3(0f,0f,ccwNeeded);
float videoRatio = (float)webcamTexture.width/(float)webcamTexture.height;
AspectRatioFitter rawImageARF = rawimage.GetComponent<AspectRatioFitter>();
rawImageARF.aspectRatio = videoRatio;
if ( webcamTexture.videoVertically$$anonymous$$irrored )
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
Debug.Log ("videoRatio: "+ videoRatio.ToString());
}
}
Now our aspect ratio should be 1:1 because we are using a 480x480 RawImage but the aspect is ratio is incorrect and is stretched or squashed depending how i hold the device. I've included two images so that you can see what i mean:
is it not possible to make a 1:1 ratio? I've even tried forcing it, but no result. please if anyone can explain or shed some light on the matter it would be appreciated.
We really want to use the 480X480 resolution for our image. so if anyone has a solution for me, that would be awesome. On the other side, if this is a problem, should i submit a bug report?
Thank you in advance for reading this.
I guess the problem is you are getting (for example) 640x480 images from the camera when you're holding the device in horizontal position, and 480x640 in vertical position. You then squeeze these images to fit into 480x480, so once you get horizontal squeezed images (640 to 480 width) and once vertical squeezed images (640 to 480 height).
Yes, that's most likely the problem. You can't really force a camera chip to a certain aspect ratio since the native aspect ratio is always there. The image would need to be "cropped" in some way so some information of the image would be lost. It certainly doesn't automatically crop the image since there are multiple ways how you could crop an image to a certain resolution.
So you would need to:
either crop the image manually by copying only the part you want into your square texture
or change UV coordinates of the quad so it only shows the wanted portion
In the following calculations we assume that width is the larger edge and height is the smaller one. If the image is rotated you have to take that into account.
You probably want to crop evenly left and right. So the amount you have to crop on the larger side is:
float amount = (width - height) * 0.5f;
So "amount" pixels need to be removed from both sides of the larger side.
To calculate the UV coordinates it's quite similar
float u = (1f - height / width) * 0.5f;
While the "v" coordinates stay at max (one is "0" the other is "1") the u coordinate (along the larger edge of your image) need to be "u" and "1f - u"
Answer by MorphVGX · Jan 07, 2017 at 01:05 AM
What I found is that the ratio will be correct after the device is set and you call Play() on the WebcamTexture.
Your answer
Follow this Question
Related Questions
Is it possible to render Unity graphics elements on top of iPhone / Android video feed? 2 Answers
how to convert Input.mousePosition into iphone/android accelerometer? 1 Answer
GUI Styles for iPhone/Android - font/button sizing? 3 Answers
Zero-ing the Input.acceleration.z 0 Answers
Best way to create/design modular Player 2 Answers