Android : OpenCV Turning off camera preview - android

I am writing a Augmented reality demo for the Epson BT 200 glasses, I have sample which I have up and running that if you point it at a certain picture, it detects it and renders a cube on top of it.
Now obviously this is fine for a phone, but for see thru glasses I want it to work but not show the camera feed. I thought turning off the view would stop it, or setting the visibility to gone. But still does not work.
The only work around I have found so far is by not setting the OpenGL render to transparent pixels
// The OpenCV loader callback.
private BaseLoaderCallback mLoaderCallback =
new BaseLoaderCallback(this) {
#Override
public void onManagerConnected(final int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
Log.d(TAG, "OpenCV loaded successfully");
mCameraView.enableView();
mCameraView.enableFpsMeter();
mBgr = new Mat();
final ARFilter starryNight;
try {
// Define The Starry Night to be 1.0 units tall.
starryNight = new ImageDetectionFilter(
CameraActivity.this,
R.drawable.the_lab,
mCameraProjectionAdapter, 1.0);
} catch (IOException e) {
Log.e(TAG, "Failed to load drawable: " +
"starry_night");
e.printStackTrace();
break;
}
final ARFilter akbarHunting;
try {
// Define Akbar Hunting with Cheetahs to be 1.0
// units wide.
akbarHunting = new ImageDetectionFilter(
CameraActivity.this,
R.drawable.akbar_hunting_with_cheetahs,
mCameraProjectionAdapter, 1.0);
} catch (IOException e) {
Log.e(TAG, "Failed to load drawable: " +
"akbar_hunting_with_cheetahs");
e.printStackTrace();
break;
}
mImageDetectionFilters = new ARFilter[] {
//new NoneARFilter(),
starryNight,
akbarHunting
};
mARRenderer.filter = mImageDetectionFilters[
mImageDetectionFilterIndex];
break;
default:
super.onManagerConnected(status);
break;
}
}
};
// Suppress backward incompatibility errors because we provide
// backward-compatible fallbacks.
#SuppressLint("NewApi")
#Override
protected void onCreate(final Bundle savedInstanceState) {
goFullScreen();
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mCameraIndex = savedInstanceState.getInt(
STATE_CAMERA_INDEX, 0);
mImageSizeIndex = savedInstanceState.getInt(
STATE_IMAGE_SIZE_INDEX, 0);
mImageDetectionFilterIndex = savedInstanceState.getInt(
STATE_IMAGE_DETECTION_FILTER_INDEX, 0);
} else {
mCameraIndex = 0;
mImageSizeIndex = cameraSize; // was 0
mImageDetectionFilterIndex = 0;
}
final FrameLayout layout = new FrameLayout(this);
layout.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
layout.setBackgroundColor(Color.RED);
setContentView(layout);
mCameraView = new JavaCameraView(this, mCameraIndex);
mCameraView.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
layout.addView(mCameraView);
//mCameraView.setVisibility(View.INVISIBLE);
GLSurfaceView glSurfaceView = new GLSurfaceView(this);
glSurfaceView.getHolder().setFormat(
PixelFormat.TRANSPARENT);
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 0, 0);
glSurfaceView.setZOrderOnTop(true);
glSurfaceView.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
layout.addView(glSurfaceView);
mCameraProjectionAdapter = new CameraProjectionAdapter();
mARRenderer = new ARCubeRenderer();
mARRenderer.cameraProjectionAdapter =
mCameraProjectionAdapter;
// Earlier, we defined the printed image's size as 1.0
// unit.
// Define the cube to be half this size.
mARRenderer.scale = 0.5f;
glSurfaceView.setRenderer(mARRenderer);
final Camera camera;
if (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.GINGERBREAD) {
CameraInfo cameraInfo = new CameraInfo();
Camera.getCameraInfo(mCameraIndex, cameraInfo);
mIsCameraFrontFacing =
(cameraInfo.facing ==
CameraInfo.CAMERA_FACING_FRONT);
mNumCameras = Camera.getNumberOfCameras();
camera = Camera.open(mCameraIndex);
} else { // pre-Gingerbread
// Assume there is only 1 camera and it is rear-facing.
mIsCameraFrontFacing = false;
mNumCameras = 1;
camera = Camera.open();
}
final Parameters parameters = camera.getParameters();
camera.release();
mSupportedImageSizes =
parameters.getSupportedPreviewSizes();
final Size size = mSupportedImageSizes.get(mImageSizeIndex);
mCameraProjectionAdapter.setCameraParameters(
parameters, size);
// Earlier, we defined the printed image's size as 1.0
// unit.
// Leave the near and far clip distances at their default
// values, which are 0.1 (one-tenth the image size) and
// 10.0 (ten times the image size).
mCameraView.setMaxFrameSize(size.width, size.height);
mCameraView.setCvCameraViewListener(this);
}

Related

Android camera2 output to ImageReader format YUV_420_888 still slow

I'm trying to get the Android camera2 running in the background service, then process the frame in the callback ImageReader.OnImageAvailableListener. I already use the suggested raw format YUV_420_888 to get max fps, however I only get around 7fps on the resolution 640x480. This is even slower than what I get using the old Camera interface( I want to upgrade to Camera2 to get higher fps ) or with the OpenCV JavaCameraView( I can't use this because I need to run processing in the background service ).
Below is my service class. What am I missing?
My phone is Redmi Note 3 running Android 5.0.2
public class Camera2ServiceYUV extends Service {
protected static final String TAG = "VideoProcessing";
protected static final int CAMERACHOICE = CameraCharacteristics.LENS_FACING_BACK;
protected CameraDevice cameraDevice;
protected CameraCaptureSession captureSession;
protected ImageReader imageReader;
// A semaphore to prevent the app from exiting before closing the camera.
private Semaphore mCameraOpenCloseLock = new Semaphore(1);
public static final String RESULT_RECEIVER = "resultReceiver";
private static final int JPEG_COMPRESSION = 90;
public static final int RESULT_OK = 0;
public static final int RESULT_DEVICE_NO_CAMERA= 1;
public static final int RESULT_GET_CAMERA_FAILED = 2;
public static final int RESULT_ALREADY_RUNNING = 3;
public static final int RESULT_NOT_RUNNING = 4;
private static final String START_SERVICE_COMMAND = "startServiceCommands";
private static final int COMMAND_NONE = -1;
private static final int COMMAND_START = 0;
private static final int COMMAND_STOP = 1;
private boolean mRunning = false;
public Camera2ServiceYUV() {
}
public static void startToStart(Context context, ResultReceiver resultReceiver) {
Intent intent = new Intent(context, Camera2ServiceYUV.class);
intent.putExtra(START_SERVICE_COMMAND, COMMAND_START);
intent.putExtra(RESULT_RECEIVER, resultReceiver);
context.startService(intent);
}
public static void startToStop(Context context, ResultReceiver resultReceiver) {
Intent intent = new Intent(context, Camera2ServiceYUV.class);
intent.putExtra(START_SERVICE_COMMAND, COMMAND_STOP);
intent.putExtra(RESULT_RECEIVER, resultReceiver);
context.startService(intent);
}
// SERVICE INTERFACE
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
switch (intent.getIntExtra(START_SERVICE_COMMAND, COMMAND_NONE)) {
case COMMAND_START:
startCamera(intent);
break;
case COMMAND_STOP:
stopCamera(intent);
break;
default:
throw new UnsupportedOperationException("Cannot start the camera service with an illegal command.");
}
return START_STICKY;
}
#Override
public void onDestroy() {
try {
captureSession.abortCaptures();
} catch (CameraAccessException e) {
Log.e(TAG, e.getMessage());
}
captureSession.close();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
// CAMERA2 INTERFACE
/**
* 1. The android CameraManager class is used to manage all the camera devices in our android device
* Each camera device has a range of properties and settings that describe the device.
* It can be obtained through the camera characteristics.
*/
public void startCamera(Intent intent) {
final ResultReceiver resultReceiver = intent.getParcelableExtra(RESULT_RECEIVER);
if (mRunning) {
resultReceiver.send(RESULT_ALREADY_RUNNING, null);
return;
}
mRunning = true;
CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
try {
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
String pickedCamera = getCamera(manager);
Log.e(TAG,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA " + pickedCamera);
manager.openCamera(pickedCamera, cameraStateCallback, null);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(pickedCamera);
Size[] jpegSizes = null;
if (characteristics != null) {
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.YUV_420_888);
}
int width = 640;
int height = 480;
// if (jpegSizes != null && 0 < jpegSizes.length) {
// width = jpegSizes[jpegSizes.length -1].getWidth();
// height = jpegSizes[jpegSizes.length - 1].getHeight();
// }
// for(Size s : jpegSizes)
// {
// Log.e(TAG,"Size = " + s.toString());
// }
// DEBUG
StreamConfigurationMap map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
return;
}
Log.e(TAG,"Width = " + width + ", Height = " + height);
Log.e(TAG,"output stall duration = " + map.getOutputStallDuration(ImageFormat.YUV_420_888, new Size(width,height)) );
Log.e(TAG,"Min output stall duration = " + map.getOutputMinFrameDuration(ImageFormat.YUV_420_888, new Size(width,height)) );
// Size[] sizeList = map.getInputSizes(ImageFormat.YUV_420_888);
// for(Size s : sizeList)
// {
// Log.e(TAG,"Size = " + s.toString());
// }
imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 2 /* images buffered */);
imageReader.setOnImageAvailableListener(onImageAvailableListener, null);
Log.i(TAG, "imageReader created");
} catch (CameraAccessException e) {
Log.e(TAG, e.getMessage());
resultReceiver.send(RESULT_DEVICE_NO_CAMERA, null);
}catch (InterruptedException e) {
resultReceiver.send(RESULT_GET_CAMERA_FAILED, null);
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
catch(SecurityException se)
{
resultReceiver.send(RESULT_GET_CAMERA_FAILED, null);
throw new RuntimeException("Security permission exception while trying to open the camera.", se);
}
resultReceiver.send(RESULT_OK, null);
}
// We can pick the camera being used, i.e. rear camera in this case.
private String getCamera(CameraManager manager) {
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
int cOrientation = characteristics.get(CameraCharacteristics.LENS_FACING);
if (cOrientation == CAMERACHOICE) {
return cameraId;
}
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
return null;
}
/**
* 1.1 Callbacks when the camera changes its state - opened, disconnected, or error.
*/
protected CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice camera) {
Log.i(TAG, "CameraDevice.StateCallback onOpened");
mCameraOpenCloseLock.release();
cameraDevice = camera;
createCaptureSession();
}
#Override
public void onDisconnected(#NonNull CameraDevice camera) {
Log.w(TAG, "CameraDevice.StateCallback onDisconnected");
mCameraOpenCloseLock.release();
camera.close();
cameraDevice = null;
}
#Override
public void onError(#NonNull CameraDevice camera, int error) {
Log.e(TAG, "CameraDevice.StateCallback onError " + error);
mCameraOpenCloseLock.release();
camera.close();
cameraDevice = null;
}
};
/**
* 2. To capture or stream images from a camera device, the application must first create
* a camera capture captureSession.
* The camera capture needs a surface to output what has been captured, in this case
* we use ImageReader in order to access the frame data.
*/
public void createCaptureSession() {
try {
cameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), sessionStateCallback, null);
} catch (CameraAccessException e) {
Log.e(TAG, e.getMessage());
}
}
protected CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession session) {
Log.i(TAG, "CameraCaptureSession.StateCallback onConfigured");
// The camera is already closed
if (null == cameraDevice) {
return;
}
// When the captureSession is ready, we start to grab the frame.
Camera2ServiceYUV.this.captureSession = session;
try {
session.setRepeatingRequest(createCaptureRequest(), null, null);
} catch (CameraAccessException e) {
Log.e(TAG, e.getMessage());
}
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession session) {
Log.e(TAG, "CameraCaptureSession.StateCallback onConfigureFailed");
}
};
/**
* 3. The application then needs to construct a CaptureRequest, which defines all the capture parameters
* needed by a camera device to capture a single image.
*/
private CaptureRequest createCaptureRequest() {
try {
/**
* Check other templates for further details.
* TEMPLATE_MANUAL = 6
* TEMPLATE_PREVIEW = 1
* TEMPLATE_RECORD = 3
* TEMPLATE_STILL_CAPTURE = 2
* TEMPLATE_VIDEO_SNAPSHOT = 4
* TEMPLATE_ZERO_SHUTTER_LAG = 5
*
* TODO: can set camera features like auto focus, auto flash here
* captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
*/
CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
// captureRequestBuilder.set(CaptureRequest.EDGE_MODE,
// CaptureRequest.EDGE_MODE_OFF);
// captureRequestBuilder.set(
// CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE,
// CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON);
// captureRequestBuilder.set(
// CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE,
// CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
// captureRequestBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE,
// CaptureRequest.NOISE_REDUCTION_MODE_OFF);
// captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
// CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
//
// captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
// captureRequestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true);
captureRequestBuilder.addTarget(imageReader.getSurface());
return captureRequestBuilder.build();
} catch (CameraAccessException e) {
Log.e(TAG, e.getMessage());
return null;
}
}
/**
* ImageReader provides a surface for the camera to output what has been captured.
* Upon the image available, call processImage() to process the image as desired.
*/
private long frameTime = 0;
private ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Log.i(TAG, "called ImageReader.OnImageAvailable");
Image img = reader.acquireLatestImage();
if (img != null) {
if( frameTime != 0 )
{
Log.e(TAG, "fps = " + (float)(1000.0 / (float)(SystemClock.elapsedRealtime() - frameTime)) + " fps");
}
frameTime = SystemClock.elapsedRealtime();
img.close();
}
}
};
private void processImage(Image image) {
Mat outputImage = imageToMat(image);
Bitmap bmp = Bitmap.createBitmap(outputImage.cols(), outputImage.rows(), Bitmap.Config.ARGB_8888);
Utils.bitmapToMat(bmp, outputImage);
Point mid = new Point(0, 0);
Point inEnd = new Point(outputImage.cols(), outputImage.rows());
Imgproc.line(outputImage, mid, inEnd, new Scalar(255, 0, 0), 2, Core.LINE_AA, 0);
Utils.matToBitmap(outputImage, bmp);
Intent broadcast = new Intent();
broadcast.setAction("your_load_photo_action");
broadcast.putExtra("BitmapImage", bmp);
sendBroadcast(broadcast);
}
private Mat imageToMat(Image image) {
ByteBuffer buffer;
int rowStride;
int pixelStride;
int width = image.getWidth();
int height = image.getHeight();
int offset = 0;
Image.Plane[] planes = image.getPlanes();
byte[] data = new byte[image.getWidth() * image.getHeight() * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];
byte[] rowData = new byte[planes[0].getRowStride()];
for (int i = 0; i < planes.length; i++) {
buffer = planes[i].getBuffer();
rowStride = planes[i].getRowStride();
pixelStride = planes[i].getPixelStride();
int w = (i == 0) ? width : width / 2;
int h = (i == 0) ? height : height / 2;
for (int row = 0; row < h; row++) {
int bytesPerPixel = ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8;
if (pixelStride == bytesPerPixel) {
int length = w * bytesPerPixel;
buffer.get(data, offset, length);
// Advance buffer the remainder of the row stride, unless on the last row.
// Otherwise, this will throw an IllegalArgumentException because the buffer
// doesn't include the last padding.
if (h - row != 1) {
buffer.position(buffer.position() + rowStride - length);
}
offset += length;
} else {
// On the last row only read the width of the image minus the pixel stride
// plus one. Otherwise, this will throw a BufferUnderflowException because the
// buffer doesn't include the last padding.
if (h - row == 1) {
buffer.get(rowData, 0, width - pixelStride + 1);
} else {
buffer.get(rowData, 0, rowStride);
}
for (int col = 0; col < w; col++) {
data[offset++] = rowData[col * pixelStride];
}
}
}
}
// Finally, create the Mat.
Mat mat = new Mat(height + height / 2, width, CV_8UC1);
mat.put(0, 0, data);
return mat;
}
private void stopCamera(Intent intent) {
ResultReceiver resultReceiver = intent.getParcelableExtra(RESULT_RECEIVER);
if (!mRunning) {
resultReceiver.send(RESULT_NOT_RUNNING, null);
return;
}
closeCamera();
resultReceiver.send(RESULT_OK, null);
mRunning = false;
Log.d(TAG, "Service is finished.");
}
/**
* Closes the current {#link CameraDevice}.
*/
private void closeCamera() {
try {
mCameraOpenCloseLock.acquire();
if (null != captureSession) {
captureSession.close();
captureSession = null;
}
if (null != cameraDevice) {
cameraDevice.close();
cameraDevice = null;
}
if (null != imageReader) {
imageReader.close();
imageReader = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
mCameraOpenCloseLock.release();
}
}
}
I bumped into this problem recently when I try to upgrade my AR app from camera1 to camera2 API, I used a mid-range device for testing (Meizu S6) which has Exynos 7872 CPU and Mali-G71 GPU. What I want to achieve is a steady 30fps AR experience.
But through the migration I found that its quite tricky to get a decent preview frame rate using Camera2 API.
I configured my capture request using TEMPLATE_PREVIEW
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Then I Put 2 surfaces, one for preview which is a surfaceTexture at size 1280x720,
another ImageReader at size 1280x720 for image processing.
mImageReader = ImageReader.newInstance(
mVideoSize.getWidth(),
mVideoSize.getHeight(),
ImageFormat.YUV_420_888,
2);
List<Surface> surfaces =new ArrayList<>();
Surface previewSurface = new Surface(mSurfaceTexture);
surfaces.add(previewSurface);
mPreviewBuilder.addTarget(previewSurface);
Surface frameCaptureSurface = mImageReader.getSurface();
surfaces.add(frameCaptureSurface);
mPreviewBuilder.addTarget(frameCaptureSurface);
mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), captureCallback, mBackgroundHandler);
Everything works as expected, my TextureView gets updated and framecallback gets called too Except ... the frame rate is about 10 fps and I haven't even do any image processing yet.
I have experimented many Camera2 API settings include SENSOR_FRAME_DURATION and different ImageFormat and size combinations but none of them improve the frame rate. But if I just remove the ImageReader from output surfaces, then preview gets 30 fps easily!
So I guess the problem is By adding ImageReader as Camera2 output surface decreased the preview frame rate drastically. At least on my case, so what is the solution?
My solution is glReadPixel
I know glReadPixel is one of the evil things because it copy bytes from GPU to main memory and also causing OpenGL to flush draw commands thus for sake of performance we'd better avoid using it. But its surprising that glReadPixel is actually pretty fast and providing much better frame rate then ImageReader's YUV_420_888 output.
In addition to reduce the memory overhead I make another draw call with smaller frame buffer like 360x640 instead of preview's 720p dedicated for feature detection.
Based on the implementation of camera2 by the openCV library.
I had the same problem, then I noticed this piece of code in the openCV code for the JavaCamera2View, you need to change the settings of the CaptureRequest.Builder that way:
CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
It changed the fps from 10fps to around 28-30fps for me. Worked for me with two target surfaces, one surface of the preview textureview, the second of the ImageReader:
Surface readerSurface = imageReader.getSurface();
Surface surface = new Surface(surfaceTexture);
captureBuilder.addTarget(surface);
captureBuilder.addTarget(readerSurface);
Cannot post a comment (not enough reps). But running into the same issue with Redmi 6.
If using the the TextureView for previewing the camera output I get around 30 fps but replacing it with ImageReader it went down to 8/9 fps. All the camera configs are same in either case.
Interesting enough, on trying out the CameraXBasic, it showed the same issue. The updates from Camera were sluggish. But the android-Camera2Basic (using TextureView) was running without any issues.
Update: 1
Tested out with lowering the preview size from 1280x720 to 640x480, and as expected saw a better performance.
This is what I know after tweaking with it a little, the problem lies on ImageReader's maxImage param, I changed it from 2 to 3 to 56, it changed the fps quite a lot, what I think is the surface which we render to camera2 from ImageReader has a tendency to block the process of saving the camera's image to the buffer/cache when Image class from ImageReader.OnImageAvailableListener is being processed or isn't released, or we could say the camera wanna use the buffer but it doesn't have enough buffer, so when we increase the max buffer of imageReader, we could give space to camera2 to save the image.

How to display my image in ImageView (CUSTOM CAMERA)

I created a custom camera app that saves the image in SD.
I have another activity that involves an ImageView.
I want to display the photo taken from camera in ImageView.
How should I do that?
public class CameraActivity extends Activity {
private static final String TAG = "CUSTOMCAM";
public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;
private Camera mCamera;
private CameraPreview mPreview;
private SensorManager sensorManager = null;
private int orientation;
private ExifInterface exif;
private int deviceHeight;
private Button ibRetake;
private Button ibUse;
private Button ibCapture;
private FrameLayout flBtnContainer;
private File sdRoot;
private String dir;
private String fileName;
private ImageView rotatingImage;
private int degrees = -1;
private Uri imageUri;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
// Setting all the path for the image
sdRoot = Environment.getExternalStorageDirectory();
dir = "/DCIM/Camera/";
// Getting all the needed elements from the layout
rotatingImage = (ImageView) findViewById(R.id.imageView1);
ibRetake = (Button) findViewById(R.id.ibRetake);
ibUse = (Button) findViewById(R.id.ibUse);
ibCapture = (Button) findViewById(R.id.ibCapture);
flBtnContainer = (FrameLayout) findViewById(R.id.flBtnContainer);
// Getting the sensor service.
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
// Selecting the resolution of the Android device so we can create a
// proportional preview
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
deviceHeight = display.getHeight();
// Add a listener to the Capture button
ibCapture.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mCamera.takePicture(null, null, mPicture);
}
});
// Add a listener to the Retake button
ibRetake.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Deleting the image from the SD card/
File discardedPhoto = new File(sdRoot, dir + fileName);
discardedPhoto.delete();
// Restart the camera preview.
mCamera.startPreview();
// Reorganize the buttons on the screen
flBtnContainer.setVisibility(LinearLayout.VISIBLE);
ibRetake.setVisibility(LinearLayout.GONE);
ibUse.setVisibility(LinearLayout.GONE);
}
});
// Add a listener to the Use button
ibUse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Everything is saved so we can quit the app.
finish();
Intent intent = new Intent(CameraActivity.this, PicturePreview.class);
startActivity(intent);
}
});
}
private PictureCallback mPicture = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
// Replacing the button after a photho was taken.
flBtnContainer.setVisibility(View.GONE);
ibRetake.setVisibility(View.VISIBLE);
ibUse.setVisibility(View.VISIBLE);
// File name of the image that we just took.
fileName = "IMG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()).toString() + ".jpg";
// Creating the directory where to save the image. Sadly in older
// version of Android we can not get the Media catalog name
File mkDir = new File(sdRoot, dir);
mkDir.mkdirs();
// Main file where to save the data that we recive from the camera
File pictureFile = new File(sdRoot, dir + fileName);
try {
FileOutputStream purge = new FileOutputStream(pictureFile);
purge.write(data);
purge.close();
} catch (FileNotFoundException e) {
Log.d("DG_DEBUG", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("DG_DEBUG", "Error accessing file: " + e.getMessage());
}
// Adding Exif data for the orientation. For some strange reason the
// ExifInterface class takes a string instead of a file.
try {
exif = new ExifInterface("/sdcard/" + dir + fileName);
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "" + orientation);
exif.saveAttributes();
} catch (IOException e) {
e.printStackTrace();
}
//SendBroadcasts let's us instantly update the SD card with our image
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://"+Environment.getExternalStorageDirectory())));
}
};
private void createCamera() {
// Create an instance of Camera
mCamera = getCameraInstance();
Setting the right parameters in the camera
Camera.Parameters params = mCamera.getParameters();
mCamera.setParameters(params);
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
// Calculating the width of the preview so it is proportional.
float widthFloat = (float) (deviceHeight) * 4 / 3;
int width = Math.round(widthFloat);
// Resizing the LinearLayout so we can make a proportional preview. This
// approach is not 100% perfect because on devices with a really small
// screen the the image will still be distorted - there is place for
// improvment.
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(width, deviceHeight);
preview.setLayoutParams(layoutParams);
// Adding the camera preview after the FrameLayout and before the button
// as a separated element.
preview.addView(mPreview, 0);
}
#Override
protected void onResume() {
super.onResume();
// Test if there is a camera on the device and if the SD card is
// mounted.
if (!checkCameraHardware(this)) {
Intent i = new Intent(this, NoCamera.class);
startActivity(i);
finish();
} else if (!checkSDCard()) {
Intent i = new Intent(this, NoSDCard.class);
startActivity(i);
finish();
}
// Creating the camera
createCamera();
// Register this class as a listener for the accelerometer sensor
////sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
super.onPause();
// release the camera immediately on pause event
releaseCamera();
// removing the inserted view - so when we come back to the app we
// won't have the views on top of each other.
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.removeViewAt(0);
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
private boolean checkSDCard() {
boolean state = false;
String sd = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(sd)) {
state = true;
}
return state;
}
/**
* A safe way to get an instance of the Camera object.
*/
public static Camera getCameraInstance() {
Camera c = null;
try {
// attempt to get a Camera instance
c = Camera.open();
} catch (Exception e) {
// Camera is not available (in use or does not exist)
}
// returns null if camera is unavailable
return c;
}
/**
* Putting in place a listener so we can get the sensor data only when
* something changes.
*/
public void onSensorChanged(SensorEvent event) {
synchronized (this) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
RotateAnimation animation = null;
if (event.values[0] < 4 && event.values[0] > -4) {
if (event.values[1] > 0 && orientation != ExifInterface.ORIENTATION_ROTATE_90) {
// UP
orientation = ExifInterface.ORIENTATION_ROTATE_90;
animation = getRotateAnimation(270);
degrees = 270;
} else if (event.values[1] < 0 && orientation != ExifInterface.ORIENTATION_ROTATE_270) {
// UP SIDE DOWN
orientation = ExifInterface.ORIENTATION_ROTATE_270;
animation = getRotateAnimation(90);
degrees = 90;
}
} else if (event.values[1] < 4 && event.values[1] > -4) {
if (event.values[0] > 0 && orientation != ExifInterface.ORIENTATION_NORMAL) {
// LEFT
orientation = ExifInterface.ORIENTATION_NORMAL;
animation = getRotateAnimation(0);
degrees = 0;
} else if (event.values[0] < 0 && orientation != ExifInterface.ORIENTATION_ROTATE_180) {
// RIGHT
orientation = ExifInterface.ORIENTATION_ROTATE_180;
animation = getRotateAnimation(180);
degrees = 180;
}
}
if (animation != null) {
rotatingImage.startAnimation(animation);
}
}
}
}
/**
* Calculating the degrees needed to rotate the image imposed on the button
* so it is always facing the user in the right direction
*
* #param toDegrees
* #return
*/
private RotateAnimation getRotateAnimation(float toDegrees) {
float compensation = 0;
if (Math.abs(degrees - toDegrees) > 180) {
compensation = 360;
}
// When the device is being held on the left side (default position for
// a camera) we need to add, not subtract from the toDegrees.
if (toDegrees == 0) {
compensation = -compensation;
}
// Creating the animation and the RELATIVE_TO_SELF means that he image
// will rotate on it center instead of a corner.
RotateAnimation animation = new RotateAnimation(degrees, toDegrees - compensation, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
// Adding the time needed to rotate the image
animation.setDuration(250);
// Set the animation to stop after reaching the desired position. With
// out this it would return to the original state.
animation.setFillAfter(true);
return animation;
}
/**
* STUFF THAT WE DON'T NEED BUT MUST BE HEAR FOR THE COMPILER TO BE HAPPY.
*/
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.custom_cam, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
this is the code
and then I have a second activity that I need to call the image taken
Keep the saved image path in string. Then pass it to other activity with Bundle.
eg.
In your camera activity
under your ibUse.setOnClickListener. Like this;
ibUse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Everything is saved so we can quit the app.
finish();
Intent intent = new Intent(CameraActivity.this, PicturePreview.class);
Bundle extras = new Bundle();
extras.putString("ImagePath", path);
intent.putExtras(extras);
startActivity(intent);
}
});
In your preview activity under onCreate method
Bundle bundle = getIntent().getExtras();
String path = bundle.getString("ImagePath");
ImageView image = (ImageView) findViewById(R.id.image);
File imgFile = new File(path);
if(imgFile.exists()){
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
image.setImageBitmap(myBitmap);
}

Camera2 callback equivalent

I got a RA application using Camera API and I want to integrate Camera2.
Is an equivalent exists to get each preview frame in order to sent it to JMonkeyEngine ?
Here is my code using Camera API :
public void onResume() {
mStopPreview = false;
try {
mCamera = CameraOldManager.getCamera();
if (mCamera != null) {
// initialize camera parameters
CameraOldManager.initializeCameraParameters(mCameraWidth, mCameraHeight);
CameraOldManager.setCameraDisplayOrientation(mActivity, 0, mCamera);
preparePreviewCallbackBuffer();
mJmeApp.setCameraVideoResolution(mCameraWidth, mCameraHeight);
mPreview = new CameraPreview(mActivity, mCamera, mCameraCallback);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(1, 1);
mActivity.addContentView(mPreview, lp);
}
} catch (Exception e) {
Log.e(TAG, "Exception init camera: " + e.getMessage());
}
}
// prepares the Camera preview callback buffers.
public void preparePreviewCallbackBuffer() {
int pformat;
pformat = mCamera.getParameters().getPreviewFormat();
Log.e(TAG, "PREVIEW format: " + pformat);
// Get pixel format information to compute buffer size.
PixelFormat info = new PixelFormat();
PixelFormat.getPixelFormatInfo(pformat, info);
// The actual preview width and height.
// They can differ from the requested width mDesiredmCameraWidth
//mPreviewWidth = mCamera.getParameters().getPreviewSize().width;
//mPreviewHeight = mCamera.getParameters().getPreviewSize().height;
int bufferSizeRGB565 = mCameraWidth * mCameraHeight * 2 + 4096;
//Delete buffer before creating a new one.
mPreviewBufferRGB565 = null;
mPreviewBufferRGB565 = new byte[bufferSizeRGB565];
mPreviewByteBufferRGB565 = ByteBuffer.allocateDirect(mPreviewBufferRGB565.length);
mCameraJMEImageRGB565 = new Image(Image.Format.RGB565, mCameraWidth,
mCameraHeight, mPreviewByteBufferRGB565);
}
// Implement the interface for getting copies of preview frames
private final Camera.PreviewCallback mCameraCallback = new Camera.PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera c) {
if (c != null && !mStopPreview && mJmeApp != null && mJmeApp.isFirstModelLoaded()) {
mPreviewByteBufferRGB565.clear();
// Perform processing on the camera preview data.
if (mPixelFormatConversionNeeded) {
RAUtils.yCbCrToRGB565(data, mCameraWidth, mCameraHeight,
mPreviewBufferRGB565);
mPreviewByteBufferRGB565.put(mPreviewBufferRGB565);
} else {
mPreviewByteBufferRGB565.put(data);
}
mCameraJMEImageRGB565.setData(mPreviewByteBufferRGB565);
mJmeApp.setVideoBGTexture(mCameraJMEImageRGB565);
}
}
};
What I need is to get frames to give them to JME.

startPreview failed but not all devices

I'm getting an error startPreview failed but not all devices.
In Motorola RAZR and Samsung Galaxy S3, it's working very well.
Some people told me they got the same problem in other devices (Galaxy SII Lite, Galaxy Ace Duos, Samsung Galaxy Y, etc)
I'm trying to test in a Samsung Galaxy Y and here's what I got in Logcat
java.lang.RuntimeException: startPreview failed
at android.hardware.Camera.startPreview(Native Method)
at br.com.timo.tubagram.CameraSurfaceView.surfaceCreated(CameraSurfaceView.java:47)
at android.view.SurfaceView.updateWindow(SurfaceView.java:601)
at android.view.SurfaceView.updateWindow(SurfaceView.java:413)
at android.view.SurfaceView.dispatchDraw(SurfaceView.java:358)
at android.view.View.draw(View.java:7083)
at android.view.SurfaceView.draw(SurfaceView.java:344)
at android.view.View.buildDrawingCache(View.java:6842)
at android.view.View.getDrawingCache(View.java:6628)
at android.view.ViewGroup.drawChild(ViewGroup.java:1571)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
at android.view.View.draw(View.java:7083)
at android.widget.FrameLayout.draw(FrameLayout.java:357)
at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
at android.view.View.draw(View.java:7083)
at android.widget.FrameLayout.draw(FrameLayout.java:357)
at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2108)
at android.view.ViewRoot.draw(ViewRoot.java:1540)
at android.view.ViewRoot.performTraversals(ViewRoot.java:1276)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3770)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:670)
at dalvik.system.NativeStart.main(Native Method)
And here is my code
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, PreviewCallback{
private SurfaceHolder holder;
private Camera camera;
private Camera.Parameters parameters;
boolean front = false;
public CameraSurfaceView(Context context) {
super(context);
this.holder = this.getHolder();
this.holder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
this.holder = holder;
camera = Camera.open();
camera.setPreviewDisplay(holder);
parameters = parametrosCamera();
camera.setParameters(parameters);
camera.setDisplayOrientation(90);
camera.startPreview();
} catch (IOException ioe) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
}
private Parameters parametrosCamera(){
Parameters parameters = camera.getParameters();
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
if (sizes != null){
Size min = sizes.get(0);
for (Size size : sizes){
if (size.width < min.width){
min = size;
}else{
parameters.setPreviewSize(min.width, min.height);
parameters.setPictureSize(min.width, min.height);
}
}
parameters.set("orientation", "portrait");
parameters.setRotation(90);
}
if (parameters.getFlashMode() != null){
parameters.setFlashMode(Parameters.FLASH_MODE_AUTO);
}
return parameters;
}
}
And my PrincipalActivity
public class PrincipalActivity extends Activity{
Camera camera;
File sdImageMainDirectory;
CameraSurfaceView cameraSurfaceView;
Button principalActivity_bt_TirarFoto;
Button principalActivity_bt_VirarFoto;
Button principalActivity_bt_Aceitar;
Button principalActivity_bt_Cancelar;
FrameLayout preview;
ImageView principalActivity_iv_UltimaFoto;
HandlePictureStorage hps;
int wid = 0;
boolean imageSelected = false;
boolean front = false;
String caminhoImagens;
String url;
// File storagePath = new File(Environment.getExternalStorageDirectory() + "/Tubagram/");
#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
public void onCreate(Bundle savedInstanceState) {
Log.i("PrincipalActivity","onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.principal_activity);
principalActivity_bt_TirarFoto = (Button) findViewById(R.id.principalActivity_bt_TirarFoto);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
cameraSurfaceView = new CameraSurfaceView(principalActivity_bt_TirarFoto.getContext());
cameraSurfaceView.setSoundEffectsEnabled(true);
cameraSurfaceView.setDrawingCacheEnabled(true);
preview = (FrameLayout) findViewById(R.id.principalActivity_fl_Camera);
preview.addView(cameraSurfaceView);
principalActivity_bt_TirarFoto.setSoundEffectsEnabled(true);
principalActivity_bt_TirarFoto.setOnClickListener(new OnClickListener() {
#SuppressLint("NewApi")
#Override
public void onClick(View v) {
Log.i("PrincipalActivity","onClick - TirarFoto");
camera = cameraSurfaceView.getCamera();
camera.takePicture(new ShutterCallback() {
#Override
public void onShutter() {
AudioManager mgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mgr.playSoundEffect(AudioManager.FLAG_PLAY_SOUND);
}
}, null, hps = new HandlePictureStorage());
imageSelected = false;
mostrarBotoesConfirma();
}
});
principalActivity_bt_Aceitar = (Button) findViewById(R.id.principalActivity_bt_Aceitar);
principalActivity_bt_Aceitar.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i("PrincipalActivity","onClick - Aceitar");
if (verificaInstagram()){
ByteArrayOutputStream stream = new ByteArrayOutputStream();
if (imageSelected){
Bitmap bitmap = ((BitmapDrawable)cameraSurfaceView.getBackground()).getBitmap();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
}else{
hps.getBitmap().compress(Bitmap.CompressFormat.PNG, 100, stream);
}
salvarImagemSelecionada(stream.toByteArray());
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
shareIntent.setType("image/*");
caminhoImagens = getRealPathFromURI(Uri.parse(url));
Log.i("Caminho imagem: ", caminhoImagens);
shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + caminhoImagens));
shareIntent.setPackage("com.instagram.android");
startActivity(shareIntent);
// }
}else{
Toast.makeText(v.getContext(), "Você não possui o Instagram no seu smartphone!", Toast.LENGTH_SHORT).show();
}
}
});
principalActivity_bt_Cancelar = (Button) findViewById(R.id.principalActivity_bt_Cancelar);
principalActivity_bt_Cancelar.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i("PrincipalActivity","onClick - Cancelar");
esconderBotoesConfirma();
cameraSurfaceView.setBackgroundColor(Color.TRANSPARENT);
cameraSurfaceView.voltarCamera();
}
});
int qtdCameras = Camera.getNumberOfCameras();
principalActivity_bt_VirarFoto = (Button) findViewById(R.id.principalActivity_bt_VirarFoto);
if(qtdCameras > 1){
principalActivity_bt_VirarFoto.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Log.i("PrincipalActivity","onClick - VirarCamera");
Thread t = new Thread(){
#Override
public void run() {
cameraSurfaceView.flipit();
front = cameraSurfaceView.getFront();
}
};
t.start();
}
});
}else{
principalActivity_bt_VirarFoto.setVisibility(View.INVISIBLE);
}
LinearLayout principalActivity_ll_Molduras = (LinearLayout) findViewById(R.id.principalActivity_ll_Molduras);
principalActivity_ll_Molduras.setVisibility(View.VISIBLE);
List<Integer> listaMoldurasMenores = new ArrayList<Integer>();
final List<Integer> listaMoldurasMaiores = new ArrayList<Integer>();
// listaMoldurasMenores.add(R.drawable.moldura_menor0);
listaMoldurasMenores.add(R.drawable.moldura_menor1);
listaMoldurasMenores.add(R.drawable.moldura_menor2);
listaMoldurasMenores.add(R.drawable.moldura_menor3);
listaMoldurasMenores.add(R.drawable.moldura_menor4);
listaMoldurasMenores.add(R.drawable.moldura_menor5);
listaMoldurasMenores.add(R.drawable.moldura_menor6);
listaMoldurasMaiores.add(R.drawable.moldura_maior1);
listaMoldurasMaiores.add(R.drawable.moldura_maior2);
listaMoldurasMaiores.add(R.drawable.moldura_maior3);
listaMoldurasMaiores.add(R.drawable.moldura_maior4);
listaMoldurasMaiores.add(R.drawable.moldura_maior5);
listaMoldurasMaiores.add(R.drawable.moldura_maior6);
for (int i = 0; i < listaMoldurasMenores.size(); i++) {
final ImageView imagem_moldura = new ImageView(this);
imagem_moldura.setScaleType(ScaleType.FIT_XY);
imagem_moldura.setId(i);
imagem_moldura.setImageResource(listaMoldurasMenores.get(i));
imagem_moldura.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i("PrincipalActivity","onClick - Molduras");
ImageView imagem_moldura_maior = new ImageView(v.getContext());
imagem_moldura_maior.setImageResource(listaMoldurasMaiores.get(imagem_moldura.getId()));
preview.setForeground(imagem_moldura_maior.getDrawable());
}
});
principalActivity_ll_Molduras.addView(imagem_moldura,i);
}
principalActivity_iv_UltimaFoto = (ImageView) findViewById(R.id.principalActivity_iv_UltimaFoto);
principalActivity_iv_UltimaFoto.setAdjustViewBounds(false);
Uri uri = buscaUltimaFotoAlbum();
Drawable backgroundGaleria;
if (uri != null){
String caminhosImagensGaleria = getRealPathFromURI(uri);
backgroundGaleria = Drawable.createFromPath(caminhosImagensGaleria);
principalActivity_iv_UltimaFoto.setBackgroundDrawable(backgroundGaleria);
}else{
principalActivity_iv_UltimaFoto.setBackgroundResource(R.drawable.box_imagem_album);
}
principalActivity_iv_UltimaFoto.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI);
final int ACTION_SELECT_IMAGE = 1;
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 10);
intent.putExtra("aspectY", 10);
intent.putExtra("outputX", 256);
intent.putExtra("outputY", 256);
intent.putExtra("scale", true);
intent.putExtra("return-data", true);
startActivityForResult(intent,ACTION_SELECT_IMAGE);
}
});
}
EDIT 1 - 06/20/2013
I change a little my code and now runs in my Galaxy Y but my FrameLayout with the camera isn't working. I getting a black screen on FrameLayout.
Anyone knows why?
What I change:
I added this line in my constructor
this.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
I changed my surfaceCreated and surfaceChanged to this
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
try {
camera.stopPreview();
parameters = parametrosCamera();
camera.setParameters(parameters);
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(holder);
camera.startPreview();
}
catch (IOException e) {
}
catch (Exception e){
}
}
#SuppressLint("NewApi")
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open(0);
camera.setPreviewDisplay(this.holder);
camera.startPreview();
} catch (IOException ioe) {
} catch (Exception e){
}
}
P.S.
I added some Log's to get the size my setPreviewSize is getting with my method
private Parameters parametersCamera(){
Parameters parameters = camera.getParameters();
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
if (sizes != null){
Size min = sizes.get(0);
for (Size size : sizes){
if (size.width < min.width){
min = size;
}else{
parameters.setPreviewSize(min.width, min.height);
parameters.setPictureSize(min.width, min.height);
Log.i("Ultima Camera Width: " + min.width, "Ultima Camera Height: " + min.height);
}
}
parameters.set("orientation", "portrait");
parameters.setRotation(90);
}
if (parameters.getFlashMode() != null){
parameters.setFlashMode(Parameters.FLASH_MODE_AUTO);
}
return parameters;
}
and I added a Log in surfaceChanged to get the width and height (I don't use this width and height) and see if is the same and I get this result's
Motorola RAZR HD (works verywell)
surfaceChanged: 540 x 573
method parametrosCamera: 640 x 480
Samsung Galaxy Y (don't show my preview)
surfaceChanged: 240 x 162 (W x H)
method parametrosCamera: 320 x 240
and in my method parametersCamera I use these two lines
parameters.set("orientation", "portrait");
parameters.setRotation(90);
I think the answer to my question is in this part of my code.
You seem to be looking for the minimal supported preview size. But if this size is not supported as picture size, your code will initialize the camera into an unsupported state. Some devices may choose to fail to open preview in such state.
I am not sure you really need picture size to be equal to preview frame size. If you don't, you can simply iterate separately on the values from parameters.getSupportedPictureSizes().
Another common mistake (not necessarily applicable to your use case) is rooted in that the sizes for rear-facing camera do not match those of the front-facing camera. Therefore, the size must always be recalculated when you switch the camera.
Question isnt using camera manager related library, so it isnt useful to question poster (its ancient I assume he is already fixed or dont care anymore to issue), but this answer may help or fix on user that facing issue startpreview error only on some various devices.
Causes
After deep debug, I found that camera manager library try to use largest suitable resolution if no exact size match.
As in CameraConfiguration.findBestPreviewSizeValue() :
// If no exact match, use largest preview size. This was not a great
// idea on older devices because
// of the additional computation needed. We're likely to get here on
// newer Android 4+ devices, where
// the CPU is much more powerful.
if (!supportedPreviewSizes.isEmpty()) {
Camera.Size largestPreview = supportedPreviewSizes.get(0);
Point largestSize = new Point(largestPreview.width, largestPreview.height);
Log.i(TAG, "Using largest suitable preview size: " + largestSize);
return largestSize;
}
This is good on the device's manufacture is properly set on the supported preview sizes.
But thing sometime happens! Device may report ridiculous high resolution which overwhelming the device on startPreview(), which an internal driver error occur 'preview timeout', only visible on catlog.
Lets fix it!
Use closest resolution to the screen instead!
Modifiying CameraConfiguration.java or maybe inside CameraConfigurationUtils.java:
... Skip lines until you find next pattern (take note that your source may be a slightly different!)
+ Add lines
- Remove lines
...
...
public static Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) {
...
...
// Find a suitable size, with max resolution
int maxResolution = 0;
Camera.Size maxResPreviewSize = null;
+ double closestResolutionDrift = 1024*1024;
+ Camera.Size closestResolution = null;
for (Camera.Size size : rawSupportedSizes) {
...
...
Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint);
return exactPoint;
}
+
+ double drift = (maybeFlippedWidth * maybeFlippedHeight)-(screenResolution.x * screenResolution.y);
+ if (drift < closestResolutionDrift && resolution>(screenResolution.x * screenResolution.y)) {
+ closestResolutionDrift = drift;
+ closestResolution = size;
+ }
...
...
//If no exact match, use largest preview size. This was not a great idea on older devices because
//of the additional computation needed. We're likely to get here on newer Android 4+ devices, where
//the CPU is much more powerful.
- if (maxResPreviewSize != null) {
- Point largestSize = new Point(maxResPreviewSize.width, maxResPreviewSize.height);
- Log.i(TAG, "Using largest suitable preview size: " + largestSize);
- return largestSize;
- }
+ //if (maxResPreviewSize != null) {
+ // Point largestSize = new Point(maxResPreviewSize.width, maxResPreviewSize.height);
+ // Log.i(TAG, "Using largest suitable preview size: " + largestSize);
+ // return largestSize;
+ //}
+
+ // Dont! Some low end device still report ridiculous high resolution which overwhelming startPreview!
+ if(closestResolution!=null){
+ Point closestSize = new Point(closestResolution.width, closestResolution.height);
+ Log.i(TAG, "Using closest suitable preview size: " + closestSize);
+ return closestSize;
+ }

How to capture an image in android with fixed size?

I used the following code to capture image. Everything works fine, when i capture the image it has 2592x1944 size and the image is captured in landscape mode. Now i want to capture the image with the size of 534x534. I changed this parameter values params.setPictureSize(534, 534); Nothing will change. How can i do this. Thanks in advance.
DgCamActivity.java
public class DgCamActivity extends Activity implements SensorEventListener {
private Camera mCamera;
private CameraPreview mPreview;
private SensorManager sensorManager = null;
private int orientation;
private ExifInterface exif;
private int deviceHeight;
private Button ibRetake;
private Button ibUse;
private Button ibCapture;
// private FrameLayout flBtnContainer;
private File sdRoot;
private String dir;
private String fileName;
// private ImageView rotatingImage;
private int degrees = -1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
// Setting all the path for the image
sdRoot = Environment.getExternalStorageDirectory();
dir = "/SimpleCamera/";
// Getting all the needed elements from the layout
// rotatingImage = (ImageView) findViewById(R.id.imageView1);
ibRetake = (Button) findViewById(R.id.ibRetake);
ibUse = (Button) findViewById(R.id.ibUse);
ibCapture = (Button) findViewById(R.id.ibCapture);
// flBtnContainer = (FrameLayout) findViewById(R.id.flBtnContainer);
// Getting the sensor service.
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
// Selecting the resolution of the Android device so we can create a
// proportional preview
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
deviceHeight = display.getHeight();
// Add a listener to the Capture button
ibCapture.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mCamera.takePicture(null, null, mPicture);
}
});
// Add a listener to the Retake button
ibRetake.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Deleting the image from the SD card/
File discardedPhoto = new File(sdRoot, dir + fileName);
discardedPhoto.delete();
// Restart the camera preview.
mCamera.startPreview();
// Reorganize the buttons on the screen
// flBtnContainer.setVisibility(LinearLayout.VISIBLE);
ibRetake.setVisibility(LinearLayout.GONE);
ibUse.setVisibility(LinearLayout.GONE);
}
});
// Add a listener to the Use button
ibUse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Everything is saved so we can quit the app.
finish();
}
});
}
private void createCamera() {
// Create an instance of Camera
mCamera = getCameraInstance();
// Setting the right parameters in the camera
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPictureSizes();
Log.v("SUPORTED SIZE IS>>>>>.", params.getSupportedPictureSizes() + "");
Log.v("SUPORTED SIZE IS>>>>>.", sizes.size() + "");
params.setPictureSize(1600, 1200);
params.setPictureFormat(PixelFormat.JPEG);
params.setJpegQuality(100);
mCamera.setParameters(params);
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
RelativeLayout preview = (RelativeLayout) findViewById(R.id.camera_preview);
// Calculating the width of the preview so it is proportional.
float widthFloat = (float) (deviceHeight) * 4 / 3;
int width = Math.round(widthFloat);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
preview.setLayoutParams(layoutParams);
preview.addView(mPreview, 0);
}
#Override
protected void onResume() {
super.onResume();
createCamera();
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
super.onPause();
releaseCamera();
RelativeLayout preview = (RelativeLayout) findViewById(R.id.camera_preview);
preview.removeViewAt(0);
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
public static Camera getCameraInstance() {
Camera c = null;
try {
// attempt to get a Camera instance
c = Camera.open();
} catch (Exception e) {
// Camera is not available (in use or does not exist)
}
// returns null if camera is unavailable
return c;
}
private PictureCallback mPicture = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
ibRetake.setVisibility(View.VISIBLE);
ibUse.setVisibility(View.VISIBLE);
// File name of the image that we just took.
fileName = "IMG_"
+ new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date()).toString() + ".jpg";
File mkDir = new File(sdRoot, dir);
mkDir.mkdirs();
// Main file where to save the data that we recive from the camera
File pictureFile = new File(sdRoot, dir + fileName);
try {
FileOutputStream purge = new FileOutputStream(pictureFile);
purge.write(data);
purge.close();
} catch (FileNotFoundException e) {
Log.d("DG_DEBUG", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("DG_DEBUG", "Error accessing file: " + e.getMessage());
}
try {
exif = new ExifInterface("/sdcard/" + dir + fileName);
exif.setAttribute(ExifInterface.TAG_ORIENTATION, ""
+ orientation);
exif.saveAttributes();
} catch (IOException e) {
e.printStackTrace();
}
}
};
/**
* Putting in place a listener so we can get the sensor data only when
* something changes.
*/
public void onSensorChanged(SensorEvent event) {
synchronized (this) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
RotateAnimation animation = null;
if (event.values[0] < 4 && event.values[0] > -4) {
if (event.values[1] > 0
&& orientation != ExifInterface.ORIENTATION_ROTATE_90) {
// UP
orientation = ExifInterface.ORIENTATION_ROTATE_90;
animation = getRotateAnimation(270);
degrees = 270;
} else if (event.values[1] < 0
&& orientation != ExifInterface.ORIENTATION_ROTATE_270) {
// UP SIDE DOWN
orientation = ExifInterface.ORIENTATION_ROTATE_270;
animation = getRotateAnimation(90);
degrees = 90;
}
} else if (event.values[1] < 4 && event.values[1] > -4) {
if (event.values[0] > 0
&& orientation != ExifInterface.ORIENTATION_NORMAL) {
// LEFT
orientation = ExifInterface.ORIENTATION_NORMAL;
animation = getRotateAnimation(0);
degrees = 0;
} else if (event.values[0] < 0
&& orientation != ExifInterface.ORIENTATION_ROTATE_180) {
// RIGHT
orientation = ExifInterface.ORIENTATION_ROTATE_180;
animation = getRotateAnimation(180);
degrees = 180;
}
}
if (animation != null) {
// rotatingImage.startAnimation(animation);
}
}
}
}
/**
* Calculating the degrees needed to rotate the image imposed on the button
* so it is always facing the user in the right direction
*
* #param toDegrees
* #return
*/
private RotateAnimation getRotateAnimation(float toDegrees) {
float compensation = 0;
if (Math.abs(degrees - toDegrees) > 180) {
compensation = 360;
}
// When the device is being held on the left side (default position for
// a camera) we need to add, not subtract from the toDegrees.
if (toDegrees == 0) {
compensation = -compensation;
}
// Creating the animation and the RELATIVE_TO_SELF means that he image
// will rotate on it center instead of a corner.
RotateAnimation animation = new RotateAnimation(degrees, toDegrees
- compensation, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
// Adding the time needed to rotate the image
animation.setDuration(250);
// Set the animation to stop after reaching the desired position. With
// out this it would return to the original state.
animation.setFillAfter(true);
return animation;
}
/**
* STUFF THAT WE DON'T NEED BUT MUST BE HEAR FOR THE COMPILER TO BE HAPPY.
*/
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
CameraPreview.java
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mHolder.setSizeFromLayout();
mHolder.setFixedSize(100, 100);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the
// preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d("DG_DEBUG", "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// make any resize, rotate or reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d("DG_DEBUG", "Error starting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
}
test.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<RelativeLayout
android:id="#+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" >
</RelativeLayout>
<RelativeLayout
android:id="#+id/relativeLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="41dp" >
<Button
android:id="#+id/ibCapture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/relativeLayout1"
android:layout_alignLeft="#+id/camera_preview"
android:text="Capture" />
<Button
android:id="#+id/ibRetake"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="36dp"
android:layout_toRightOf="#+id/ibCapture"
android:text="ReTake" />
<Button
android:id="#+id/ibUse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="38dp"
android:text="Save" />
</RelativeLayout>
</RelativeLayout>
I believe Android will not allow for arbitrary image sizes when taking a picture, you should use the parameters.getSupportedPictureSizes() method to query the supported image sizes.
I suspect you would have to choose a big enough size to cut your desired 534x534 patch from. You could do this by using BitmapFactory methods to decode the picture that was taken and then use bitmap.getPixels() method to extract the desired patch size, or something like bitmap.createScaledBitmap() to scale your picture to the desired size.
After you have your correctly sized bitmap, you could just use bitmap.compress() to save your image, if that's the final format you are going for.

Categories

Resources