- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我已经设法使用自定义滤镜(灰度、色调等)进行相机预览。通过操纵 RGB 数组,然后将其绘制回 Canvas ,然后在表面 View 中显示,此自定义滤镜与预览回调一起应用。
这样做的缺点是 FPS 非常低。对于如此低的 FPS,如果我不使用 Asynctask 在后台线程中执行此操作,它就会在 UI 线程中执行过多的工作。所以我尝试使用 Asynctask 进行相机操作(我的主要目的是让 UI 即使在相机预览回调的繁重工作下仍然可以完美运行)。
但即使在我使用了 Asynctask 之后,它也没有太大帮助。所以我想知道是我的实现有误还是因为即使使用 asynctask UI 线程仍会受到影响?
我的代码 fragment 如下:
CameraActivity.java
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("ACTIVITY_LIFECYCLE","CameraActivity: onCreate");
setContentView(R.layout.camera_layout);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
protected void onResume() {
Log.d("ACTIVITY_LIFECYCLE","CameraActivity: onResume");
if(preview == null){
preview = new CameraPreviewAsync(this,camera);
preview.execute();
}
super.onResume();
}
@Override
protected void onPause() {
Log.d("ACTIVITY_LIFECYCLE","CameraActivity: onPause");
if(preview!=null){
preview.cancel(true);
camera = preview.getCamera();
if(camera!=null){
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
preview.setCamera(camera);
}
preview = null;
}
super.onPause();
}
@Override
public void onDestroy(){
Log.d("ACTIVITY_LIFECYCLE","CameraActivity: onDestroy");
super.onDestroy();
}
CameraPreviewAsync.java:
private final String TAG = "CameraPreviewAsync";
private CameraActivity camAct;
private Camera mCamera;
private int cameraId;
private SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
private boolean isPreviewRunning = false;
private int[] rgbints;
private int width;
private int height;
private Bitmap mBitmap;
public CameraPreviewAsync(CameraActivity act, Camera cam){
this.camAct = act;
this.mCamera = cam;
this.mSurfaceView = (SurfaceView) act.findViewById(R.id.surfaceView);
}
public void resetSurface(){
if(mCamera!=null){
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
int tempId = R.id.surfaceView;
RelativeLayout buttonBar = (RelativeLayout) camAct.findViewById(R.id.buttonBar);
((RelativeLayout) camAct.findViewById(R.id.preview)).removeAllViews();
SurfaceView newSurface = new SurfaceView(camAct);
newSurface.setId(tempId);
RelativeLayout.LayoutParams layParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
layParams.alignWithParent = true;
newSurface.setLayoutParams(layParams);
((RelativeLayout) camAct.findViewById(R.id.preview)).addView(newSurface);
((RelativeLayout) camAct.findViewById(R.id.preview)).addView(buttonBar);
}
@Override
protected void onPreExecute() {
//Things to do before doInBackground executed
Log.d(TAG,"onPreExecute");
RelativeLayout.LayoutParams layParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
layParams.alignWithParent = true;
mSurfaceView.setLayoutParams(layParams);
//Check number of camera in the device, if less than 2 then remove swap button
if (Camera.getNumberOfCameras() < 2) {
((RelativeLayout) camAct.findViewById(R.id.buttonBar)).removeViewAt(R.id.cameraSwap);
}
//Opening the camera
cameraId = findBackFacingCamera();
if (cameraId < 0) {
cameraId = findFrontFacingCamera();
if (cameraId < 0)
Toast.makeText(camAct, "No camera found.", Toast.LENGTH_LONG).show();
else
mCamera = Camera.open(cameraId);
} else {
mCamera = Camera.open(cameraId);
}
//invalidate the menu bar and show menu appropriately
camAct.invalidateOptionsMenu();
// get Camera parameters and set it to Auto Focus
if(mCamera!=null){
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
}
}
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... params) {
//Things to do in the background thread
Log.d(TAG,"doInBackground");
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(surfaceCallback);
return null;
}
@Override
protected void onPostExecute(Void values) {
//Things to do after doInBackground
Log.d(TAG,"onPostExecute");
}
@Override
protected void onCancelled(){
super.onCancelled();
}
/*
* ************************************************************************************
* SURFACEHOLDER CALLBACK
* ************************************************************************************
*/
SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG,"surfaceCreated!!");
if(CameraActivity.filterMode == CameraActivity.NORMAL_FILTER){
try {
if (mCamera != null) {
mCamera.startPreview();
mCamera.setPreviewDisplay(holder);
}else{
Log.d(TAG,"CAMERA IS NULL in surfaceCreated!!");
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}else{
synchronized(mSurfaceView){
if(isPreviewRunning){
return;
}else{
mSurfaceView.setWillNotDraw(false);
if(mCamera!=null){
isPreviewRunning = true;
Camera.Parameters p = mCamera.getParameters();
List<Size> sizes = p.getSupportedPreviewSizes();
Size size = p.getPreviewSize();
width = size.width;
height = size.height;
p.setPreviewFormat(ImageFormat.NV21);
showSupportedCameraFormats(p);
mCamera.setParameters(p);
rgbints = new int[width * height];
mCamera.startPreview();
mCamera.setPreviewCallback(previewCallback);
}
}
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG,"surfaceDestroyed!");
if(CameraActivity.filterMode == CameraActivity.NORMAL_FILTER){
if (mCamera != null) {
mCamera.stopPreview();
isPreviewRunning = false;
}
}else{
synchronized(mSurfaceView){
if(mCamera!=null){
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
isPreviewRunning = false;
}
}
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.d(TAG,"surfaceChanged!");
}
};
/*
* ************************************************************************************
* CAMERA PREVIEW CALLBACK
* ************************************************************************************
*/
Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (!isPreviewRunning)
return;
Canvas resCanvas = null;
if (mHolder == null) {
return;
}
try {
synchronized (mHolder) {
resCanvas = mHolder.lockCanvas(null);
int resCanvasW = resCanvas.getWidth();
int resCanvasH = resCanvas.getHeight();
if(mBitmap == null){
mBitmap = Bitmap.createBitmap (width, height, Bitmap.Config.ARGB_8888);
}
decodeYUV(rgbints, data, width, height);
Canvas canvas = new Canvas(mBitmap);
//Setting the filter
if(camAct.getCustomFilter().equalsIgnoreCase("NORMAL")) ;//don't change the rgb value
if(camAct.getCustomFilter().equalsIgnoreCase("GRAYSCALE")) rgbints = grayscale(rgbints);
if(camAct.getCustomFilter().equalsIgnoreCase("INVERT")) rgbints = invert(rgbints);
if(camAct.getCustomFilter().equalsIgnoreCase("BOOSTRED")) rgbints = boostColor(rgbints,1);
if(camAct.getCustomFilter().equalsIgnoreCase("BOOSTGREEN")) rgbints = boostColor(rgbints,2);
if(camAct.getCustomFilter().equalsIgnoreCase("BOOSTBLUE")) rgbints = boostColor(rgbints,3);
if(camAct.getCustomFilter().equalsIgnoreCase("NOISE")) rgbints = noise(rgbints);
if(camAct.getCustomFilter().equalsIgnoreCase("HUE")) rgbints = hue(rgbints);
if(camAct.getCustomFilter().equalsIgnoreCase("SATURATION")) rgbints = saturation(rgbints);
if(camAct.getCustomFilter().equalsIgnoreCase("ENGRAVE")) rgbints = engrave(rgbints);
if(camAct.getCustomFilter().equalsIgnoreCase("EMBOSS")) rgbints = emboss(rgbints);
// draw the decoded image, centered on canvas
canvas.drawBitmap(rgbints, 0, width, 0,0, width, height, false, null);
resCanvas.drawBitmap (mBitmap, resCanvasW-((width+resCanvasW)>>1), resCanvasH-((height+resCanvasH)>>1),null);
}
} catch (Exception e){
e.printStackTrace();
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (resCanvas != null) {
mHolder.unlockCanvasAndPost(resCanvas);
}
}
}
};
非常感谢任何帮助! :) 提前谢谢大家!
最佳答案
也许我的回答对你来说太晚了,但我正在研究同一个主题,所以我想无论如何我都会分享我的发现......
首先,如果在 AsyncTask 上调用了 Camera 的“打开”,然后该线程存在并占用存在 - 我们真的不能期望回调来自它,对吧。所以,如果我们想要回调 - 那么我们需要有一个线程,它的生命周期至少与我们想要回调的时间一样长。
但等等,还有更多... Camera.PreviewCallback 的文档不是最清楚的,但其中一个不好的提示是“此回调在 event thread open(int) 上调用被叫来的。” “事件”线程是什么意思?好吧,这不是很清楚 - 但查看 Android 代码并进行试验 - 他们需要的是一个包含 Looper 的线程。可能细节太多,但在 Camera 构造函数(从 open 方法调用)中有代码尝试首先获取当前线程的 Looper,如果不存在 - 它尝试获取主线程循环器 - 它继续存在界面线程。 Camera 然后使用 Handler 来分派(dispatch)回调,并通过它初始化的循环器来分派(dispatch)其他方法。现在您可能明白为什么即使您从另一个线程打开相机,您也会在主线程上收到回调 - 您的工作线程没有循环程序 - 所以相机默认使用主线程。
我从我的工作线程获得了回调,我在这些线程的方法中使用了 HandlerThread:
private void startCamera() {
if (mCameraThread == null) {
mCameraThread = new HandlerThread(CAMERA_THREAD_NAME);
mCameraThread.start();
mCameraHandler = new Handler(mCameraThread.getLooper());
}
mCameraHandler.post(new Runnable() {
@Override
public void run() {
try {
mCamera = Camera.open();
...
我使用调试器确认我的 onPreviewFrame 确实在工作线程上运行。我还在 UI 线程上运行动画,在我将帧处理从主线程移出之前它是不稳定的,但现在像黄油一样流畅。
请注意,如果您终止工作线程,那么您的回调当然也会停止,Camera(更确切地说是 Handler)会提示您尝试使用死线程。
顺便说一句,作为一种替代解决方案,当然可以在主线程上调用回调,但可以将帧数据的处理委托(delegate)给单独的线程。
关于Android:带有预览回调的相机异步任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19216893/
有人能给我一些代码示例,了解如何从相机捕获“完整”图像,然后在“startActivityForResult”中将其转换为字节,以及显示在 imageView 中的位图。任何帮助将不胜感激。 山姆 最
我有一个带有两个圆的组,当我用平移过渡移动其中一个时,我应该看到静止的一个保持在中心(位于场景图的中间),而另一个移动。取而代之的是,“摄像机”跟随移动的圆圈,使其看起来好像都在分开。 有没有一种方法
我希望停止 Phonegap 将图片保存到 iOS 上的相机胶卷。 我发现了一种可能的解决方案,但我不太喜欢它。该解决方案需要通过删除这行代码来 fork phonegap API。 UIImageW
我最近开始使用 JOGL,我知道如何在 Canvas 上创建和绘制对象,但我找不到有关如何设置和旋转相机的教程或说明。我只找到了源代码,但由于我对此很陌生,所以它没有太大帮助。 有人知道一个好的教程或
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 8 年前。 Improve this ques
我想实现这样的目标: 因此,您捕获和处理的唯一内容是矩形中的区域。我需要这个,因为我想做一些 OCR 而我不想要整个屏幕。 最佳答案 也许可以帮助您这个来源,(在相机预览顶部绘制一个边界框以捕获部分图
我正在开发一个 Android 应用程序,我希望我的应用程序能够拍照并显示它们。我的问题是它制作了图片,将它存储在 SD 卡上但没有在我的应用程序中显示它,ImageView 保持空白。这是我的代码:
我正在研究 Android 相机教程,SDK 11。出于某种原因,我在 handleCameraPhoto() 中得到了一个空指针。我唯一看到的是“无法将结果 ResultInfo{who=null,
我一直在尝试实现此代码,我在其中从相机捕获图像并将其显示在我的图像查看器中,然后可以将其设置为墙纸。它在我的模拟器中运行良好,但在我的手机上,当我拍摄图像并单击“确定”时,它会强制关闭。有什么帮助吗?
我想将预览中的某些像素更改为比其余像素暗一点。假设我希望预览的上半部分比预览的下半部分暗一点。 我试图像这样使用 setPreviewCallback: camera.setPreviewCallba
我想为我的应用程序启用相机/照片库设置。我可以显示警报以编程方式启用这些吗就像应用程序启动时一样。我已附上图片以显示我希望看到我的应用程序的类似设置 对于我的应用程序,我没有看到此设置。 我的问题是这
所以我正在开发类似于相机应用程序的东西。它在原生 OpenGL 纹理上绘制实时相机预览。如果按下按钮,则会以原始形式捕获静态图像(可能比实时预览分辨率更高)。 这是我的代码的大纲。为了清楚起见,我没有
我想在我的 Android 应用程序中启动相机 Activity ,我知道该怎么做。我想问一下当相机 Activity 结束时,我如何检查它是否是用户拍摄的照片或视频? 已更新 我有一个对话框,其中询
我在横向模式下有自定义全屏摄像头。设备尺寸为 1024 x 600。 支持的预览尺寸列表 宽 x 高 176 x 144 320 x 240 352 x 288 528 x 432 640 x 480
请看下图!! 所以在这张图片中...您可以看到底部的弹出窗口,当用户“点击”“相机”按钮时,它会为用户提供 3 个选项。 那是什么观点?它是一个模态视图 Controller ,在选择一个选项时被关闭
我发布了一个应用程序,其中一项基本功能是允许用户拍照,然后将该照片保存在其外部存储上的特定文件夹中。 一切似乎都运行良好,但我现在收到两份报告,声称在拍照后单击“完成”退出相机(并返回到 Activi
我在尝试实时更换相机时遇到问题,它适用于本地视频,但远程人员看不到新相机,但仍然可以看到旧相机。我试图停止流并再次初始化,但仍然无法正常工作。这只是我的一些代码。 我到处搜索,但找不到解决方案。有人可
一个简单但非常复杂的问题:为 Flutter 相机添加点击对焦功能的最佳方法是什么? 我在整个万维网上搜索了优雅的解决方案,但一无所获。 你有想法吗? 最佳答案 我可能会迟到,但你可以试试 adv_c
我正在尝试使用 gluLookAt 方法设置 3D 相机。所以我有一个 10x10x10 的立方体,现在我想在那个立方体内移动相机。我有这样的事情: gluLookAt( camera->x,came
我赠送一个 UIImagePickerController在我的应用程序中通过在 sheet 中呈现逻辑修饰符。简而言之,以下三种类型处理显示和关闭 UIImagePickerController 的
我是一名优秀的程序员,十分优秀!