我正在制作自定义Android相机应用。到目前为止,我唯一的问题是在横向模式下调整df['my_easy_column'] = df.mycol.str[0]
进行调整(将相机旋转90度)。视图扭曲而不是正确的方向。纵向模式工作正常。我不确定问题是在textureView
方法,setupCamera()
方法还是sensorToDeviceRotation()
方法中。我还没有实现任何实际拍摄照片的东西。任何帮助表示赞赏。
编辑/更新:我更新了我的代码以添加改进。尽管如此,最初的问题仍然存在。我正在使用Pixel XL来测试此代码。我仍然不确定问题是什么。
homePage.java
configureTransform()
答案 0 :(得分:1)
您可以尝试这样的操作(在 HomePage.java 中添加此private
课程):请注意,onOrientationChanged()
方法也可以应用于xmls
:
我们保持最后的已知方向。因此,如果您首先定向相机然后将相机指向地板或天空,则TextureView
和Camera
的方向也正确。
private MyOrientationEventListener mOrientationListener;
// The degrees of the device rotated clockwise from its natural orientation.
private int mLastRawOrientation= OrientationEventListener.ORIENTATION_UNKNOWN;
//Don't forget to add **mOrientationListener = new MyOrientationEventListener(this);** on your onCreate() method
private class MyOrientationEventListener
extends OrientationEventListener {
public MyOrientationEventListener(Context context) {
super(context);
}
@Override
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWN) return;
mLastRawOrientation = orientation;
mCurrentModule.onOrientationChanged(orientation);
}
}
有关详情,请点击此链接:Camera Example
答案 1 :(得分:1)
我通过删除configureTransform()
方法,cameraModule
模块和myOrientationEventListener()
类找到了解决方案。我用transformImage()
方法替换它。然后我在onSurfaceTextureAvailable()
和onResume()
方法中调用了此方法。
我可能在旧代码中遇到的问题是我在错误的地方调用configureTransform()
方法。我从这篇文章中得到了答案:Android Camera2 Preview is rotated 90deg while in Landscape
和这个youtube教程:https://www.youtube.com/watch?v=YvS3iGKhQ_g
这些消息来源解释这个话题远比我好,所以如果遇到类似的问题,请仔细查看。
新功能代码:
homePage.java:
public class homePage extends AppCompatActivity {
private static final int CAMERA_PERMISSION = 123;
private String mCameraId;
private Size mPreviewSize;
private CaptureRequest.Builder mCaptureRequestBuilder;
private HandlerThread mBackgroundHandlerThread;
private Handler mBackgroundHandler;
private static SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 0);
ORIENTATIONS.append(Surface.ROTATION_90, 90);
ORIENTATIONS.append(Surface.ROTATION_180, 180);
ORIENTATIONS.append(Surface.ROTATION_270, 270);
}
private CameraDevice mCameraDevice;
private CameraDevice.StateCallback mCameraDeviceCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
mCameraDevice = camera;
//Toast.makeText(getApplicationContext(), "Camera connected", Toast.LENGTH_SHORT).show();
startPreview();
}
@Override
public void onDisconnected(CameraDevice camera) {
camera.close();
mCameraDevice = null;
}
@Override
public void onError(CameraDevice camera, int error) {
camera.close();
mCameraDevice = null;
}
};
private TextureView mTextureView;
private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
setupCamera(width, height);
connectCamera();
transformImage(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String permissions[],
@NonNull int[] grantResults) {
switch(requestCode) {
case CAMERA_PERMISSION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
return;
}else {
Toast.makeText(this, "Certain permissions needed to continue", Toast.LENGTH_SHORT).show();
}
break;
}
}
private boolean hasCamera() {
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
return true;
}else {
AlertDialog camAlert = new AlertDialog.Builder(homePage.this).create();
camAlert.setTitle("Alert");
camAlert.setMessage("there is no usable camera");
camAlert.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
camAlert.show();
return false;
}
}
private void setupCamera(int width, int height) {
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : cameraManager.getCameraIdList()) {
CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
if(cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
int deviceOrientation = getWindowManager().getDefaultDisplay().getRotation();
int totalRotation = sensorToDeviceRotation(cameraCharacteristics, deviceOrientation);
boolean swapRotation = totalRotation == 90 || totalRotation == 270;
int rotatedWidth = width;
int rotatedHeight = height;
if(swapRotation) {
rotatedWidth = height;
rotatedHeight = width;
}
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), rotatedWidth, rotatedHeight);
mCameraId = cameraId;
return;
}
} catch (CameraAccessException e){
e.printStackTrace();
}
}
private void closeCamera() {
if(mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}
private void connectCamera() {
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_GRANTED) {
cameraManager.openCamera(mCameraId, mCameraDeviceCallback, mBackgroundHandler);
//Toast.makeText(this, "Camera permission granted", Toast.LENGTH_SHORT).show();
} else {
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
//Toast.makeText(this, "non-marshmellow device permission granted", Toast.LENGTH_SHORT).show();
}
requestPermissions(new String[] {Manifest.permission.CAMERA}, CAMERA_PERMISSION);
}
} else {
cameraManager.openCamera(mCameraId, mCameraDeviceCallback, mBackgroundHandler);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void startPreview() {
SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface previewSurface = new Surface(surfaceTexture);
try {
mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mCaptureRequestBuilder.addTarget(previewSurface);
mCameraDevice.createCaptureSession(Arrays.asList(previewSurface),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
session.setRepeatingRequest(mCaptureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
Toast.makeText(getApplicationContext(), "Unable to set up camera preview", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void startBackgroundThread() {
mBackgroundHandlerThread = new HandlerThread("cameraString");
mBackgroundHandlerThread.start();
mBackgroundHandler = new Handler(mBackgroundHandlerThread.getLooper());
}
private void stopBackgroundThread() {
mBackgroundHandlerThread.quitSafely();
try {
mBackgroundHandlerThread.join();
mBackgroundHandlerThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static int sensorToDeviceRotation(CameraCharacteristics cameraCharacteristics,
int deviceOrientation) {
int sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
deviceOrientation = ORIENTATIONS.get(deviceOrientation);
return (sensorOrientation + deviceOrientation + 360) % 360;
}
//================new method====================================
private void transformImage(int width, int height) {
if(mPreviewSize == null || mTextureView == null) {
return;
}
Matrix matrix = new Matrix();
int rotation = getWindowManager().getDefaultDisplay().getRotation();
RectF textureRectF = new RectF(0, 0, width, height);
RectF previewRectF = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = textureRectF.centerX();
float centerY = textureRectF.centerY();
if(rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
previewRectF.offset(centerX - previewRectF.centerX(),
centerY - previewRectF.centerY());
matrix.setRectToRect(textureRectF, previewRectF, Matrix.ScaleToFit.FILL);
float scale = Math.max((float)width / mPreviewSize.getWidth(),
(float)height / mPreviewSize.getHeight());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
}
mTextureView.setTransform(matrix);
}
//===============================================================
private static class CompareSizeByArea implements Comparator<Size> {
@Override
public int compare(Size lhs, Size rhs) {
return Long.signum((long) lhs.getWidth() * lhs.getHeight() /
(long) rhs.getWidth() * rhs.getHeight());
}
}
private static Size chooseOptimalSize(Size[] choices, int width, int height) {
List<Size> bigEnough = new ArrayList<Size>();
for(Size option: choices) {
if (option.getHeight() == option.getWidth() * height / width &&
option.getWidth() >= width && option.getHeight() >= height) {
bigEnough.add(option);
}
}
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizeByArea());
} else {
return choices[0];
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_page);
hasCamera();
mTextureView = (TextureView) findViewById(R.id.textureView);
}
@Override
protected void onResume() {
super.onResume();
startBackgroundThread();
if (mTextureView.isAvailable()) {
setupCamera(mTextureView.getWidth(), mTextureView.getHeight());
connectCamera();
transformImage(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
@Override
protected void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}
}