问题
I've been working on an Android app that simply needs to retrieve and display the coordinates and RGB values of a touch event on the camera preview. I'm a beginner at this programming language and I just wanted to try this but the app keeps crashing during a touch event. Here is the code I tried in Android:
/* When copying this code set Permissions: CAMERA
* Do this by adding to AndroidManifest.xml:
* <uses-permission
android:name="android.permission.CAMERA" />
*/
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.TextView;
@SuppressWarnings("deprecation")
public class MainActivity extends Activity {
private static final String TAG = "HDMapp_MainActivity"; //ERROR Log tag
private Camera mCamera = null;
private CameraDisplay mCameraView = null;
static TextView touchView;
private Bitmap bmp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//try-catch block to try accessing the Android camera
try {
mCamera = Camera.open();
} catch(Exception e) {
Log.d(TAG, "Failed to get camera" + e.getMessage());
}
if (mCamera != null) {
mCameraView = new CameraDisplay(this, mCamera); //create SurfaceView to show camera data
FrameLayout camera_view = (FrameLayout)findViewById(R.id.camera_view);
camera_view.addView(mCameraView); //add the SurfaceView to the layout
}
touchView = (TextView)findViewById(R.id.touchView);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, 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);
}
//detects touches on screen
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
int pixelVal = bmp.getPixel(heightC,widthC);
int r = (pixelVal>>16) & 0xFF;
int g = Color.green(pixelVal);
int b = Color.blue(pixelVal);
touchView.setText("Touch coordinates--> " + "x: " +
String.valueOf(event.getX()) + " y: " + String.valueOf(event.getY()) +
" \n" + r + " \n" + g + " \n" + b);
return super.onTouchEvent(event);
}
}
I am getting NullPointerException error:
E/MessageQueue-JNI(14476): java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getPixel(int, int)' on a null object reference
I also tried using OpenCV4Android and I still get the same result:
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.TextView;
public class MainActivity extends Activity implements CvCameraViewListener2 {
private CameraBridgeViewBase mOpenCvCameraView;
private Mat mRgba;
TextView touchView;
int x, y;
double [] rgb;
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i("BaseLoaderCallback", "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i("OnCreate", "called onCreate");
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main);
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.surface_view);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
//touchView = (TextView)findViewById(R.id.touchView);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, 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);
}
@Override
public void onPause() {
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public void onResume()
{
super.onResume();
if (!OpenCVLoader.initDebug()) {
Log.d("onResume", "Internal OpenCV library not found. Using OpenCV Manager for initialization");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
} else {
Log.d("onResume", "OpenCV library found inside package. Using it!");
mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}
}
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
public void onCameraViewStarted(int width, int height) {
mRgba = new Mat(height, width, CvType.CV_8UC4);
}
public void onCameraViewStopped() {
mRgba.release();
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
// TODO Auto-generated method stub
mRgba = inputFrame.rgba();
rgb = mRgba.get(x,y);
return mRgba;
}
//detects touches on screen
@SuppressWarnings("deprecation")
@Override
public boolean onTouchEvent(MotionEvent event) {
x = (int)event.getX();
y = (int)event.getY();
//Display display = getWindowManager().getDefaultDisplay();
//int width = display.getWidth();
//int height = display.getHeight();
//double [] rgb = mRgba.get(width,height);
touchView.setText("Touch coordinates--> " + "x: " + String.valueOf(x)
+ " y: " + String.valueOf(y) + " \n" + "RGB values--> " + "Red: " + rgb[0]
+ " Green: " + rgb[1] + " Blue: " + rgb[2]);
return super.onTouchEvent(event);
}
}
Again the error is:
E/MessageQueue-JNI(15884): java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
Both these apps show the camera preview but when I touch the screen of my Nexus 7, the app stops working. Can someone please tell me what I'm doing wrong and possibly correct me?
回答1:
the second example should work, the problem is that x and y are not initialized, so in method onCameraFrame
, where you initialize rgb = mRgba.get(x,y)
, after this rgb
is still null
, since x
and y
are not initialized. Hence, your nullPointerException
when you try to print it.
What I would suggest is that you just initialize x
and y
to -1
in the beginning:
int x=-1, y=-1;
and then in touch handler method you update x and y like so:
public boolean onTouchEvent(MotionEvent event) {
x = (int)event.getX();
y = (int)event.getY();
return super.onTouchEvent(event);
}
and in the onCameraFrame method you do something like this:
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
if(x != -1 && y != -1) { //if this is true, you've touched something
rgb = mRgba.get(x,y);
touchView.setText("Touch coordinates--> " + "x: " + String.valueOf(x)
+ " y: " + String.valueOf(y) + " \n" + "RGB values--> " + "Red: " + rgb[0]
+ " Green: " + rgb[1] + " Blue: " + rgb[2]);
x = -1;
y = -1;
}
return mRgba;
}
Hope this helps
来源:https://stackoverflow.com/questions/31518499/retrieve-exact-rgb-value-from-touch-event-in-camera-preview