Is there any way to get camera's resolution ? (unless using Android from scratch)
I did not found any getter, on a setter on session.setDisplayGeometry() that is not really what I expect.
My goal is to know the camera's picture ratio to cropp it on my display since the screen and the camera do not use the same size.
Thanks.
There isn't a way to access the camera's resolution through the ARCore API in the developer preview. I asked about the resolution in comments of a separate question and it looks like the camera resolution in the developer preview will always be 1920x1080.
There is a way to get the resolution of the camera:
Frame frame = session.update();
Camera camera = frame.getCamera();
int dim[] = camera.getImageIntrinsics().getImageDimensions();
Log.d("ARCORE","Camera Dimensions: "+dim[0]+" x "+dim[1]);
But it only gives me 640x480, and I don't think there's any way to change it right now, though it may use different values on different hardware.
(ARCore 1.3)
I know it's an old question, but the answer seems to have changed since then.
Related
I'm in the process of attempting to use the camera and some motion tracking AS3 classes to detect movement in front of a ViewSonic Smart Display, for the sake of a demo. I've gotten the app and detection to function on other Android devices, but the 'Smart Display' is presenting me with some odd issues.
Taking a long shot that someone might've encountered this, but this is the very simple camera set up code I reduced the issue down to:
var camera = Camera.getCamera();
camera.setMode(stage.stageWidth, stage.stageHeight, 30, true);
var video:Video = new Video(stage.stageWidth, stage.stageHeight);
video.attachCamera(camera);
My problem lies at the point of "video.attachCamera"
For some reason, this device takes this function as "Display the video in a tiny window in the upper right hand corner" and ignores all other code, dominating the screen with blank black, and a tiny (maybe 40x20px square) of video stream.
Image of it occuring...
Any help is much appreciated, thanks
The problem might be the values that you are passing to the camera with the setMode() method. You are trying to set the camera to capture at the width/height of the stage.
The camera likely does not have such a capture resolution, and as the documentation for setMode() states, it will try to find something that is close to what you have specified:
Sets the camera capture mode to the native mode that best meets the specified requirements. If the camera does not have a native mode that matches all the parameters you pass, the runtime selects a capture mode that most closely synthesizes the requested mode. This manipulation may involve cropping the image and dropping frames.
Now, it is granted that you would expect Flash to have picked a resolution that is bigger than what is shown in your screenshot. But given the myriad of camera devices/drivers, it's possible this is not working too well in your case.
You might start off by experimenting w/more typical resolutions to capture the video: 480x320, 640x480, 800x600, or at the most 1024x768. Most applications on the web probably use the first or second capture resolutions.
So change:
camera.setMode(stage.stageWidth, stage.stageHeight, 30, true);
To:
camera.setMode(640, 480, 30, true);
Note you can display the video in any size you want, but the capture resolutions you can use depend on your camera hardware/drivers/OS/etc. Typical resolutions have a 4:3 aspect ratio and are relatively small (not the full dimensions of the screen/stage). The capture resolution you use affects the quality of video and the amount of network bandwidth you need to stream the video. Generally (for streaming), you don't want to use a big capture resolution, but maybe it's not so important in your motion capture use case.
I am attempting to allow users to record video that is a different size than the actual on-screen preview that they can see while recording. This seems to be possible from this documentation concerning the getSupportedVideoSizes function which states:
If the returned list is not null, the returned list will contain at
least one Size and one of the sizes in the returned list must be
passed to MediaRecorder.setVideoSize() for camcorder application if
camera is used as the video source. In this case, the size of the
preview can be different from the resolution of the recorded video
during video recording.
This suggests that some phones will return null from this fn (in my experience the Galaxy SIII does) but for those who do not, it is possible to provide a preview with a different resolution than the actual video. Is this understanding correct? Do some phones allow the behavior and others not?
Attempting a Solution:
In the official description of the setPreviewDisplay function, which is used in the lengthy process of setting up for video recording, it is mentioned that:
If this method is called with null surface or not called at all, media
recorder will not change the preview surface of the camera.
This seems to be what I want, but unfortunately if I do this, the whole video recording process is completely messed up. I am assuming that this function can not be passed null or not called at all in the process of recording video. Perhaps in other contexts this is okay. Unfortunately though, this does not seem to help me.
My only next steps are to look into TextureViews and to use a preview Texture as opposed to a typical SurfaceView implementation in order to use openGL to stretch the texture to my desired size that differs from the actual resolution (and crop any excess off the screen), and then to Construct a Surface for the setPreviewDisplay function with the Surface(SurfaceTexture surfaceTexture) constructor for a Surface. I would like to avoid using a TextureView due to incompatibility below ICS, and also because this adds significant complexity.
This seems like a delicate process, but I am hoping someone can offer some advice in this area.
Thank you.
a.Assume the user sets the size of x,y as video size
b.Now with getSupportedVideoSizes function get the entire list and see if x,y falls in one of them and set the MediaRecorder.setVideoSize().If x,y does not fall in the getSupportedVideoSizes list,then set the default profile for the video record.
This is about the video size
Now coming to the preview size,Not much workaround options.
Take a RelativeLayout which holds the SurfaceView.
<android.view.SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
preview is the name of the SurfaceView.
Here i have given a sample of re-sizing it to half of the width and height.
resetCamera(); //reset the camera
ViewGroup.LayoutParams params = preview.getLayoutParams();
RelativeLayout myRelLayout = (RelativeLayout) findViewById(R.id.myRelLayout);
params.width = (int) (myRelLayout.getWidth()/2);
params.height = (int)(myRelLayout.getHeight()/2);
preview.setLayoutParams(params);
initCamera(); //initiate the camera(open camera, set parameter, setPreviewDisplay,startPreview)
please look at the resolution of the preview and then scale down the height or width accordingly based on the video size.
Hope it helps.
As you mention, this is only possible when getSupportedVideoSizes() returns a non-null list.
But if you do see a non-null list, then this simple approach should work:
Set the desired preview resolution with setPreviewSize; the size you select has to be one of the sizes given from getSupportedPreviewSizes.
Set the preview display to your SurfaceView or SurfaceTexture with setPreviewDisplay or setPreviewTexture, respectively.
Start preview.
Create the media recorder, and set its video size either directly with setVideoSize using one of the sizes from getSupportedVideoSizes, or use one of the predefined Camcorder profiles to configure all the media recorder settings for a given quality/size.
Pass the camera object to MediaRecorder's setCamera call, configure the rest of the media recorder, and start recording.
On devices with a non-null getSupportedVideoSizes list, this should result in preview staying at the resolution set by your setPreviewSize call, with recording operating at the set video size/camcorder profile resolution. On devices with no supported video sizes, the preview size will be reset by the MediaRecorder to match the recording size. You should be able to test this by setting a very low preview resolution and a high recording resolution (say, 160x120 for preview, 720p for recording). It should be obvious if the MediaRecorder switches the preview resolution to 720p when recording starts, as the preview quality will jump substantially.
Note that the preview size is not directly linked to the dimensions of the display SurfaceView; the output of the camera preview will be scaled to fit into the SurfaceView, so if your SurfaceView's dimensions are, say 100x100 pixels due to your layout and device, whatever the preview resolution you use will be scaled to 100x100 for display. So you still need to make sure to keep the SurfaceView's aspect ratio correct so that the preview is not distorted.
And for power efficiency, you should not use a preview resolution much higher than the actual number of pixels in your SurfaceView, since the additional resolution will be lost in fitting the preview in the surfaceview. This is of course only possible for recording when getSupportedVideoSizes() returns a non-null value.
First, I will try to answer your specific questions.
it is possible to provide a preview with a different resolution than the actual video. Is this understanding correct?
Yes, preview size is more often than not different from recording size. Preview size is more often than not linked to your display size. So if a phone has display of CIF (352 x 288), but is capable of recording D1 (720 x 480), then preview size and recording size will be different. I feel that other experts have answered sufficiently on this point.
Do some phones allow the behavior and others not?
Most of the latest phones support this feature except maybe a few low-end ones.
Along with setPreviewDisplay, we have to consider this point also:
The one exception is that if the preview surface is not set (or set to null) before startPreview() is called, then this method may be called once with a non-null parameter to set the preview surface. (This allows camera setup and surface creation to happen in parallel, saving time.) The preview surface may not otherwise change while preview is running.
Could you please share the issue faced by you when setPreviewDisplay is invoked with a NULL surface?
I've always been under the impression that the preview and the final output are not connected in any way; meaning that I can set the preview to be some arbitrary dimension and that the final JPG will be whatever specific resolution I set in to be in the params, but I just ran into a very odd situation where the image data coming back in the byte[] that's in the jpg callback is different, depending on what dimensions I set my preview to.
Can someone enlighten me on what actual relationship the preview has on the final JPG? (or point me to documentation on said relationship).
TIA
[Edit]
As per ravi's answer, this was my assumption as well, however, I see no alternative but to surmise that they are, in fact, directly connected based on the evidence. I'll post code if necessary (though there's a lot of it) but here's what I'm doing.
I have a preview screen where the user takes a photo of themselves. I then display the picture captured (from the jpg callback bitmap data) in a subsequent draw view and allow them to trace a shape over their photo. I then pass the points of their polygon into a class that cuts that shape out of the original image, and gives back the cut image.
All of this works, BUT depending on how I present the PREVIEW, the polygon cutting class crashes on an array out of bounds index as it tries to access pixels on the final image that simply don't exist. This effect is produced EXCLUSIVELY by altering the shape of the preview View's dimensions. I'm not altering ANYTHING else in the code, and yet, just by mis-shaping my preview view, I can reproduce this error 100% of the time.
I can't see an explanation other than that the preview and the final are directly connected somehow, since I'm never operating on the preview's data, I only display it in a SurfaceView and then move on to deal exclusively with the data from the JPG callback following the user having taken their photo.
There is no relation between the preview resolution and the final image that is captured.
They are completely independent (at least for the still image capture). The preview resolution and the aspect ratio are not interrelated with the final image resolution and the aspect ratio in anyway.
In the camera application that I have written, the preview is always VGA but the image I capture varies from 5M to VGA (depending on the device capability)
Perhaps if you can explain the situation it would be more helpful.
We are currently developing a camera application and face very similiar problems. In our case, we want to display a 16:9 preview, while capturing a 4:3 picture. On most devices this works without any problems, but on some (e.g. Galaxy Nexus, LG Optimus 3D), the output camera picture depends on the preview you've chosen. In our case the outcoming pictures on that devices are distorted when the preview ratio is different from the picture ratio.
We tried to fix this, by changing the preview resolution to a better one just before capturing the image. But this does not work on some devices and occure error while starting the preview again after capturing is finished.
We also tried to fix this, by enlarging the SurfaceView to fullscreen-width and "over fullscreen"-height to make a 16:9 preview out of a 4:3 preview. But this does not work, because SurfaceViews can not be higher then screenheight.
So there IS any connection on SOME devices, and we really want to know, how to fix/workaround this.
I'm writing a small android app where a user can place an image inside the live preview of the camera and take a picture of this. The app will then combine the two images appropriately -- All of this is working fine.
I understand you can get/set the PreviewSize using Camera.getParameters(), I assume this is related to the size of the realtime "camera feed".
However, the size of my SurfaceView where the camera preview is shown is different from the reported (and used) PreviewSizes. For example, in the emulator my available SurfaceView happens to be 360x215, while the PreviewSize is 320x240. Still, the entire SurfaceView is filled with the preview.
But the picture that's generated in the end is (also?) 320x240. How does android compensate for these differences in size and aspect ratio? Is the image truncated?
Or am I simply misunderstanding what the PreviewSize is about - is this related to the size of the generated pictures, or is it related to the "realtime preview" that's projected on the SurfaceView? Are there any non-trivial Camera examples that deal with this?
I need to know how what transformation takes place to, eventually, copy/scale the image correctly into the photo, hence these questions.
I am trying to figure this out myself. Here is what I found out so far..
The surface view has an internal surface called mSurface which is actually used as camera feed and the encoder feed. So this buffer has to be the actual size at which you want do the recording.
You can set the size of this mSurface to be independent of the SurfaceView by using the setFixedSize method
Now you might want to perform a HD recording so the mSurface needs to 1280x760 resolution but you SurfaceView can't be that big (Assuming you are running it on a phone with a WVGA screen). So you try to set to a smaller resolution than 1280x760 which also maintains the same aspect ratio.
Android now performs a resizing on the HD buffer to get the preview resolution, cropping is not done, it is just resized to the SurfaceView reoslutions
So at this point both the mSurface and the previewSize that you set to the camera is the same resolution and hence the resultant video recording will also be of the same resolution.
That being said I am still struggling to get my VGA recorder to work on Nexus S, it is working on a LG Maha device. :)
I'm making an android application that uses the camera by using the built in one as an intent. I'm doing some analysis on the photo on a pixel by pixel basis. My wildfire returns 79000 pixels in a normal photo, this is making the analysis a little slow.
Is there any way to set the quality/resolution of the camera or image returned when using intents? I've had a look around on Google and the api and haven't come up with much. Anyone know if this is even possible or know of some other way to degrade the image resolution?
Any help greatly appreciated.
Why use the built in Appliction though the intent and not an application you'll write yourself by using the API ? I have seen various problems when using the camera this way; after all, if you want full control you shouldn't be using the intent. There are lots of working examples for taking photos through the API.
So, when using the camera through the API you may use the setParameters method of the Camera class to pass a CameraParameters object to your camera object and change various parameters.
The CameraParameters class contains a setPictureSize(int , int) method which you may use to change the size of your picture. You can use the getSupportedPictureSizes() method of CameraParameters to find out which picture sizes your device supports and use the one that fits you.
List<Size> sizes = mCamera.getParameters().getSupportedPictureSizes();
for (Size size : sizes) {
// Do something, e.g. :
menu.add(0, 1, 1, size.width + "x" + size.height);
}
Also, I see that you may set the format of your picture as NV21. This is a raw format and you can easily subsample the pixels of the returned image yourself (take a single pixel as the average of every 4 pixels so you will reduce both your image width and height by two) !