I am working on a camera app.The camera preview show is with 4:3 ratio,When i take a photo i get the complete image or full screen image.
Since i am showing the user a Camera Preview with 4:3 ratio, i want the user to also get the image with 4:3 ratio only.
I have seen many libraries which gives the user an option to crop, but here as i give path of the image and then it should crop the image and display it to user.
How can i achieve this ?
I don't think android has an out of the box cropper - but you can crop your own with Bitmap.createBitmap(originalBitmap, x1, y1, x2, y2)
Each Camera on each Android device has List of Preview Sizes and Picture Sizes.
Camera.Parameters parameters = camera.getParameters();
List<Size> preview_sizes = parameters.getSupportedPreviewSizes();
List<Size> pictures_sizes = parameters.getSupportedPictureSizes();
Try to loop all this Sizes and pick 4:3. So your result will be 4:3 without cropping.
Read more here.
Related
I'm working on Camera 2 API recently and my device has a 16:9 screen ratio but my camera sensor is 4:3. So all the preview size I got is 4:3. I' wondering is there any way I get a crop the size and only display the 16:9 part? I tried a long time and didn't find any help for camera 2.
My current camera code is similar to the camera 2 basic sample.
So how should I crop the preview and only display the 16:9 part on the texture view?
Thanks!!
You could create a SurfaceTexture with your ratio 4:3 instead of 16:9.
You could use the custom view from that sample project or create your own with the new ConstraintLayout and setting the ratio of height from 16:9 of your width (or inverse).
Then when you set the size of your texture:
texture.setDefaultBufferSize(width, height)
You will get not problems streching, because your texture is the same ratio as your camera output.
Hope this helps
I answered a similar question after having this same problem, and not being able to change the aspect ratio of the actual view to match the camera output (as Sulfkain's answer suggests).
Tl;dr: the answer lies in the configureTransform in Camera2BasicFragment. Although their function is mostly implemented for orientation, the scaling matrix can resolve scaling/aspect ratio issues with views that are the wrong shape for the camera output.
You have to do some debug on
setUpCameraOutputs(int width, int height)
and check the part that you are selecting the size of the output
// Danger, W.R.! Attempting to use too large a preview size could exceed the camera
// bus' bandwidth limitation, resulting in gorgeous previews but the storage of
// garbage capture data.
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), rotatedPreviewWidth,
rotatedPreviewHeight, maxPreviewWidth, maxPreviewHeight, largest);
maybe you have to hard select something there.
My application needs to capture some pictures of a given size (lets say WxH) in a portrait orientation mode.
In a general case the size WxH I want is not supported by the camera therefore I will need to crop the captured picture in order to match my specifications.
This apparently simple program is driving me crazy for the problem of "good" corrispondence among preview and picture sizes and format.
Let me explain:
I need a format (let's give some numbers: 800x600) for the output image, and I have to take pictures in a portrait screen orientation. My camera by default is in Landscape mode therefore it takes pictures with a Width much larger than the height. But since I want a portrait preview I need to rotate the image and as a consequence I get images with an height much larger than the width (the transpose of the original image I guess).
In this scenario I need to cut a horizontally extended rectangle from a bigger vertically extended rectangle and I would like to do that by having an accettable large preview.
the problem of cropping the out image from the picture does not scare me (for the moment), the mean problem is the matching among what the user sees into the preview and what the camera actually captures.
for each possible phone I need to:
- chose a suitable camera picture size with respect the desired image format
- chose a suitable camera preview size with respect to the picture size and format.
- hide the preview parts that will be cropped.
And with the constraints of no distortion and large preview.
How to do it in general?
What I thought and tried:
the main algorithm steps are:
- get the optimal picture size once known the desired format
- get the optimal preview size once known the picture size
- hide the parts not capturable of the preview
- crop the image
tried method 1)
A) I get the optimal picture size by minimizing the area difference (I could also check the aspect ratio affinity is not very important). (Size is a custom type different from Camera.Size)
public Size getOptimalPictureSize(List<Camera.Size> sizes) {
Size opt = new Size();
float objf = Float.MAX_VALUE;
float v;
for(Camera.Size s : sizes){
if(s.height<target_size.width || s.width<target_size.height)
continue;
v = (s.height-target_size.width)*s.width + (s.width-target_size.height)*target_size.width;
if(v<objf){
opt.width=s.width;
opt.height=s.height;
objf=v;
}
}
return opt;
}
B) I get the optimal preview size by finding the best compromise among different aspect ratio (with respect to the picture size) :
#Override
public Size getOptimalPreviewSize(Size picSize,List<android.hardware.Camera.Size> sizes) {
Size opt = new Size();
double objf = Double.MAX_VALUE;
double aspratio = picSize.getAspectRatio();
double v;
for(Camera.Size s : sizes){
v = Math.abs( ((double)s.width)/((double)s.height) - aspratio )/(Math.max(((double)s.width)/((double)s.height), aspratio));
if(v<objf){
objf=v;
opt.width=s.width;
opt.height=s.height;
}
}
return opt;
}
C) hiding methods for displaying only capturable parts....(discussed later)
** Trial 2) **
A) I get the picture and preview sizes by minimizing an optimality functions that weights at the same time the misfit among camera image aspect ratio and desired one and the misfit among the preview and picture aspect ratio.
public void setOptimalCameraSizes(List<Camera.Size> preview_sizes,List<Camera.Size> picture_sizes,Size preview_out, Size picture_out) {
double objf=Double.MAX_VALUE;
double tmp;
for(Camera.Size pts : picture_sizes){
for(Camera.Size pws : preview_sizes){
tmp = percv(((double)pws.height)/((double)pws.width),target_size.getAspectRatio())
+ percv(((double)pws.width)/((double)pws.height),((double)pts.width)/((double)pts.height));
if(tmp<objf){
preview_out.set(pws.width, pws.height);
picture_out.set(pts.width, pts.height);
objf=tmp;
}
}
}
}
where
percv(a,b) = |a-b|/max(|a|,|b|) measures the relative deviation (and thus is dimensionless).
C) some hiding methods...
Ok this two sizes selection methods are the best I found and chose good sizes, but they have a physiological problem that comes from the camera landscape orientation... they can only produce vertical rectangular images and this implies that when I draw the preview I can get two cases:
1. I set the surface dimensions so as not distort the preview image -> due to the huge height this reflects in a very small valid area in which the image is visible (so the user experience is hurted)
2. I set the maximum possible width -> I can obtain (it depends on the preview aspect ratio) distorted previews but much bigger than in case 1.
How to avoid these problems??
What I though is work on phase C) of the algorithm (hiding phase) and I tried to:
trial 1: make the camera preview go beyond the screen sizes. This will allow me to make an arbitrary zoom in the area of interest and make the screen crop the preview. I tried using a scrollview but it didn't work and I don't know why. The topology was simple a root scrollview and inside a FrameLayout with the attached surfaceview but the surface always filled the screen leading to horrible distortions.
trial 2: capture the camera frame and manipulate them directly by overriding the onPreviewFrame(.) method: I got a misteryous error in locking the canvas (IllegalArgumentException)
How can I solve this?
I ve created my custom camera on my app.When I press capture button it saves the taken photo where I set it before.
Everything is fine for now. But the problem is the phone saves the photo as phones pixels I mean I want to 600x600 pixel but everyphone saves the picture as its camera defaults.
How can I solve this?
I use this example for my custom camera : link
You must have to re size the bitmap of of your taken picture Like...
Bitmap b = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
profileImage.setImageBitmap(Bitmap.createScaledBitmap(b, 120, 120, false));
then after delete the previous image which one was taken by camera
Whats happen in your case:
1.) always custom camera returns it default preview size you can get your preview and picture size using the code and chooses as depending on your requirement.
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
List<Camera.Size> sizes = params.getSupportedPictureSizes()
I just setup a very basic camera preview that displays the camera full screen. I compared the smoothness of both my app and the android camera and figured that the android camera seems a lot smoother.
Why is that the case? Are there any special tricks to improve the camera preview performance?
I faced the same issue a time ago, and it turned out to be related with the camera resolution. Chances are that your Camera is initializing with the maximum available resolution, which may slow down performance during preview. Try and set a lower picture size with something like this.-
Camera.Parameters params = camera.getParameters();
params.setPictureSize(1280, 960);
camera.setParameters(params);
Notice that you'll need to set an available picture size. You can check available sizes with
camera.getParameters().getSupportedPictureSizes();
Hope it helps.
EDIT
It seems using a picture size with different aspect ratio than the default one, slows down performance as well. This is how I choose my pictureSize.-
First off, I get the aspect ratio of the camera default pictureSize
Camera.Parameters params = camera.getParameters();
defaultCameraRatio = (float) params.getPictureSize().width / (float) params.getPictureSize().height;
And then I get a lower pictureSize that fits the same ratio.-
private Size getPreferredPictureSize() {
Size res = null;
List<Size> sizes = camera.getParameters().getSupportedPictureSizes();
for (Size s : sizes) {
float ratio = (float) s.width / (float) s.height;
if (ratio == defaultCameraRatio && s.height <= PHOTO_HEIGHT_THRESHOLD) {
res = s;
break;
}
}
return res;
}
Where PHOTO_HEIGHT_THRESHOLD is the max height you want to allow.
This answer is a bit late, but after struggling with the same problem, I figured I'd share what I found.
Not only was I unable to match the stock camera's "smoothness", but I was also unable to match the metering of the stock camera. My live preview was much darker compared to the stock camera, especially in low light situations.
My solution was ultimately an FPS issue, as originally proposed by Robin in an early comment.
The default preview FPS on the Nexus 5 is a static 15 FPS. The stock android app detects and sets a preview FPS that uses a dynamic range (as long as that range includes 30fps). On a nexus 5, that range is 7fps -> 30fps. In low light the camera drops to a lower FPS to keep the preview bright, while in bright conditions it jumps to a smooth 30 fps.
Relevant code from the stock android photo app:
The call to set the FPS starts on line 1560 of com.android.camera.PhotoModule (https://android.googlesource.com/platform/packages/apps/Camera2/+/android-4.4.4_r2.0.1/src/com/android/camera/PhotoModule.java).
The utility it uses to identify the ideal FPS starts on line 833 of com.android.camera.util.CameraUtil (https://android.googlesource.com/platform/packages/apps/Camera2/+/android-4.4.4_r2.0.1/src/com/android/camera/util/CameraUtil.java)
Here's are the camera api calls to set the FPS using hard coded values (for the sake of simplicity) specific to a Nexus 5.
public void setFps(Camera camera) {
Camera.Parameters params = camera.getParameters();
params.setPreviewFpsRange(7000, 30000);
camera.setParameters(params);
}
When I am in portait mode with my android camera, the image seen is in landscape
So I wrote :
Method rotateMethod;
rotateMethod = android.hardware.Camera.class.getMethod("setDisplayOrientation", int.class);
rotateMethod.invoke(camera, 90);
It works. Yet, when I save the image, the image his in landscape (width is bigger than height)
What could I do to collect the image (bytes[]) of what my camera saw ?
Use this code:
Parameters p=camera.getParameters();
p.set("orientation", "portrait");
camera.setParameters(p);
and start camera preview