i want to use my android phone to process image, for example, make any
operation with de frame and show it with the change (show the image in
black/white, grayscale, sepia, etc).
This is my code:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback,PreviewCallback {
SurfaceHolder mHolder;
Camera mCamera;
private Parameters parameters;
private Size previewSize;
private int[] pixels;
public CameraPreview(Context context) {
super(context);
SurfaceHolder mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
this.setFocusable(true);
this.requestFocus();
}
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
}
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
setImageSize();
mCamera.startPreview();
mCamera.setPreviewCallback(this);
}
public void onPreviewFrame(byte[] data, Camera camera) {
// transforms NV21 pixel data into RGB pixels
decodeYUV420SP(pixels, data, previewSize.width, previewSize.height);
//here process the image
}
}
the problem is that i don't know how to show the new image processed.
In onPreviewFrame I convert yuv to rgb, then I process the image i.e.
convert in grayscale, but what i do for show the new image?
I need help, thanks!!!!!!!!!!!
You may want to consider using OpenCV or looking at one of their samples for image manipulations:
http://opencv.itseez.com/doc/tutorials/introduction/android_binary_package/android_binary_package.html
I read an article at: http://nhenze.net/?p=107
From what I read in the post, it's not very easy to do, because the onPreviewFrame is not synced with displaying the frames.
Instead, they use a trick to set another view on top of the SurfaceView. On that new View, they render images on an OpenGL texture with OpenGL ES.
I haven't played with it myself, but hope this will put you in the right direction.
Related
I have a camera app that had a Camera Preview which worked. The app was developed some years ago (2012) and i decided to reuse parts of its code, but, upon testing again (on same hardware i9100, different OS 4.4 vs 3.0), my camera preview image has a problem
when i move the phone, i see the image change and it responds to light and dark patterns (therefore app is communicating with camera).
this is my code (it uses deprecated method setType):
class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "TGCamera";
SurfaceHolder mHolder;
public Camera camera;
public final String fileName = "/download/CameraGPS/zdelTempPhotoPreview.jpg";
CameraPreview(Context context) {
super(context);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
camera = Camera.open();
Parameters parameter02 = camera.getParameters();
parameter02.setJpegThumbnailSize(80, 60);
parameter02.setPictureSize(640, 480);
camera.setParameters(parameter02);
try {
camera.setPreviewDisplay(holder);
camera.setDisplayOrientation(90);
Parameters parameters00 = camera.getParameters();
//parameters00.setRotation(90);
//parameters00.setFlashMode("on");
//parameters00.setJpegQuality(20);
camera.setParameters(parameters00);
camera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera arg1) {
CameraPreview.this.invalidate();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
// Because the CameraDevice object is not a shared resource, it's very
// important to release it when the activity is paused.
camera.stopPreview();
camera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
//camera.getParameters().setRotation();
//camera.getParameters().setJpegQuality(20);
//camera.getParameters().setPictureSize(width, height)
Parameters parameters = camera.getParameters();
parameters.setPreviewSize(w, h);
camera.setParameters(parameters);
camera.startPreview();
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
Log.w(TAG,"clicked in preview");
Paint p = new Paint(Color.RED);
Log.d(TAG, "draw");
canvas.drawText("PREVIEW", canvas.getWidth() / 2,
canvas.getHeight() / 2, p);
}
Any suggestions?
You cannot set the picture size and preview size to arbitrary values. Make sure you check the lists returned by getSupportedPictureSizes() and getSupportedPreviewSizes(), respectively.
Often (I don't remember if this applies to Samsung Galaxy S2), the camera does not work correctly when the aspect ratio for picture is different from the one for preview.
Furthermore, you are not supposed to draw on the preview surface, and definitely not from onPreviewFrame() callback.
The first thing would be to add camera.setPreviewDisplay(holder) in your surfaceChanged() method too
Update:
Please debug in surfaceCreated and surfaceChanged that holder.getSurface() != null
Also you should add camera.release() in surfaceDestroyed and then clean install app (uninstall first and then fresh install the app). The camera service could be hanging since a previous run of the app.
Update 2:
I just noticed that you missed registering to callbacks from the SurfaceHolder passed by the surfaceCreated() and surfaceChanged() methods. In this case it would make sense that surfaceChanged() is never reached and that means startPreview() is never actually called..
In surfaceCreated and surfaceChanged methods, please update the code to include:
mHolder.removeCallback(this); // unregister from old SurfaceHolder
holder.addCallback(this); // register to new holder
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
mHolder = holder;
I have a 3D cube and I open the camera preview, and I want to see this rotating cube displayed over the camera.
What I attempted is, inside the SurfaceChanged method of the class that implements surfaceHolder.callback, I call camera.setPreviewCallback(new PreviewCallback(){ }
as follows:
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
.......
.......
.......
camera.setPreviewCallback(new PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
glSurface.setRenderer( new MyRender());
setContentView(glSurface);
}
});
This code results in, displaying the camera preview for a few seconds until the surface is changed, then, the camera preview disappears and the 3D cube appears on a black background.
Is there anyway to show both surfaces?
As far as I recall, you have to set the CameraPreview ontop of the GlView. Thats not intuitive, but should work.
here is a link that may help you: http://digitalbreed.com/2009/android-render-opengl-on-top-of-camera-preview
You can do your own offscreen compositing, then draw the result into a single SurfaceView. See this sample code for details.
I'm trying to program Optical flow on android device.
My problem is to get two consecutive frames from camera.
That's the code to get ONE frame.
mCamera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
synchronized (SampleViewBase.this) {
mFrame2 = data;
SampleViewBase.this.notify();
}
}
});
Can't you then do something like:
private byte[] currFrame;
private byte[] prevFrame;
private void copyFrame(byte[] a){
if(a != null) prevFrame = a;
}
mCamera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
synchronized (SampleViewBase.this) {
copyFrame(currFrame);
currFrame = data;
SampleViewBase.this.notify();
}
}
});
I'm not sure that's proper Java syntax but just copy the currentFrame, before assigning data to it. Anyway, I think you can also use the VideoCapture class to obtain the frames already in a Mat format. I'm not sure if this class is still available in the latest release, but from my experience with Opencv 2.3 it was much faster to use it to grab camera frames than to use the Android camera.
I am trying to create a surface view for a camera so it renders on the surface whenever is in the view of the camera. At the moment all I can see on my camera view is a black screen view. I have tried to look on Google and here but so far I haven't found what I am looking for. Anyone can suggest me some idea.
I have written a class that can help you.
public class Preview_can_work extends Activity {
private SurfaceView surface_view;
private Camera mCamera;
SurfaceHolder.Callback sh_ob = null;
SurfaceHolder surface_holder = null;
SurfaceHolder.Callback sh_callback = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
surface_view = new SurfaceView(getApplicationContext());
addContentView(surface_view, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
if (surface_holder == null) {
surface_holder = surface_view.getHolder();
}
sh_callback = my_callback();
surface_holder.addCallback(sh_callback);
}
SurfaceHolder.Callback my_callback() {
SurfaceHolder.Callback ob1 = new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
mCamera.release();
mCamera = null;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
mCamera.startPreview();
}
};
return ob1;
}
}
in your manifest file copy this code for camera permission
<uses-permission android:name="android.permission.CAMERA"/>
Explanation:
SurfaceView is a type of View which contains a SurfaceHolder. SurfaceHolder holds the surface on which we can display our media (generally frames).
mCamera is a Camera object which will contains the camera instance.
When you want to hold default Camera instance then you can simply call Camera.open();
Camera mCamera = Camera.open();
Now you have an open camera or you are having default camera instance. Now you need to capture frames from the camera and display it on a surface. But you cannot display it without any
surface. Here the surfaceView provides surfaceHolder and surfaceHolder provides surface to display camera frames. Now when surface will be created three callback functions will be
called.
1. public void surfaceCreated(SurfaceHolder holder)
2. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
3. public void surfaceDestroyed(SurfaceHolder holder)
Note:- Surface will be destroyed when your application will go on pause.
surfaceCreated:
surfaceCreated is a callback function which will be called when your surface will be created. In this, you can open your camera and set other attributes.
surfaceChanged:
This will be called atleast one time when your surface will be created. After that it will be called whenever your surface will change(In device rotation). Here you can
start your preview because your surface have already created.
surfaceDestroyed:
This will be called every time when your surface will destroy. Now if you dont have surface then where you can display you camera frames so I have released camera by using
mCamera.release(). This is very important because if your activity will be on pause and any other activity tries to open camera then it will not able to open it as you have
already open camera. Camera is a shared resource so one time only one application can use it. So remember one thing whenever you open a camera then always release it.
stopPreview:
When you start preview then your camera starts capturing your frames and display it on a surface. Now if your surface have destroyed then you need to stop capturing frames
from camera so you have to call mCamera.stopPreview.
Make shure you added the permission :
<uses-permission android:name="android.permission.CAMERA"/>
Also these window properties:
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Post some code if that doesn't work in order to help you
I am trying to display the camera preview with an image overlay and have a button at the bottom to take the picture. I pretty much copied the API from CameraPreview and added an addcontentview which seems to work pretty well for adding an xml file which acts as my overlay. (Except that it has to be in landscape mode so I need to figure out how to either rotate all my stuff through code or, easier for me, just make sideways images :-P)
My problem is that I just can't figure out how to get my button to work correctly.
All I want to do is use the image as the background for my next activity. Anyway, this is what I've got.
public class CameraPreview extends Activity {
private Preview mPreview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
mPreview = new Preview(this);
setContentView(mPreview);
LayoutInflater inflater = getLayoutInflater();
getWindow().addContentView(inflater.inflate(R.layout.overlay, null), new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
}
}
// ----------------------------------------------------------------------
class Preview extends SurfaceView implements SurfaceHolder.Callback {
SurfaceHolder mHolder;
Camera mCamera;
Preview(Context context) {
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
mCamera.release();
mCamera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(w, h);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}
I just can't figure out where to put in my button, what to type or anything. I'm assuming its something like camera.takepicture but I can't get it to work.
Oh yea, I've spent about half the day on this one area so if you could super simplify it for me, my fried mind would appreciate it. :)
Alright, I poked around a little today with a fresh mind and decided it would be much easier to just have the user use their camera app. So I did that with a startActivityForResult and from there it was a cinch to modify my imageview with the data and I just am going to put my overlay onto the returned preview using RelativeLayout.
Thanks if you were working on this. I pulled from the question below to make mine.
How do I save data from Camera to disk using MediaStore on Android?