C# 摄像机对焦时如何实现视觉指示
当用户在我的应用程序中手动对焦(点击对焦)相机页面时,我想显示一个基本圆 我已经在下面的点击中实现了自动对焦,但我不确定如何在对焦时绘制圆,并在视图未对焦时将其关闭,以及在相机对焦时继续重新绘制圆。指示器不应该是最终照片的一部分,只是在相机对焦或不对焦时为用户提供指导 以下是我目前掌握的情况:C# 摄像机对焦时如何实现视觉指示,c#,android,xamarin,xamarin.android,android-camera,C#,Android,Xamarin,Xamarin.android,Android Camera,当用户在我的应用程序中手动对焦(点击对焦)相机页面时,我想显示一个基本圆 我已经在下面的点击中实现了自动对焦,但我不确定如何在对焦时绘制圆,并在视图未对焦时将其关闭,以及在相机对焦时继续重新绘制圆。指示器不应该是最终照片的一部分,只是在相机对焦或不对焦时为用户提供指导 以下是我目前掌握的情况: public class AutoFocusCallback : Java.Lang.Object, IAutoFocusCallback { public void OnAutoFocus(bo
public class AutoFocusCallback : Java.Lang.Object, IAutoFocusCallback
{
public void OnAutoFocus(bool success, Android.Hardware.Camera camera)
{
var parameters = camera.GetParameters();
var supportedFocusModes = parameters.SupportedFocusModes;
if (string.IsNullOrEmpty(parameters.FocusMode))
{
string focusModeContinuous = Android.Hardware.Camera.Parameters.FocusModeContinuousPicture;
string focusModeAuto = Android.Hardware.Camera.Parameters.FocusModeAuto;
if (supportedFocusModes != null && supportedFocusModes.Any())
{
if (supportedFocusModes.Contains(focusModeContinuous))
{
parameters.FocusMode = focusModeContinuous;
}
else if (supportedFocusModes.Contains(focusModeAuto))
{
parameters.FocusMode = focusModeAuto;
}
}
}
if (supportedFocusModes != null && supportedFocusModes.Any())
{
if (parameters.MaxNumFocusAreas > 0)
{
parameters.FocusAreas = null;
}
if (success)
{
CameraPage cameraPage = new CameraPage();
Canvas canvas = new Canvas();
cameraPage.Draw(canvas);
}
camera.SetParameters(parameters);
camera.StartPreview();
}
}
}
public bool OnTouch(Android.Views.View v, MotionEvent e)
{
if (camera != null)
{
var parameters = camera.GetParameters();
camera.CancelAutoFocus();
Rect focusRect = CalculateTapArea(e.GetX(), e.GetY(), 1f);
if (parameters.FocusMode != Android.Hardware.Camera.Parameters.FocusModeAuto)
{
parameters.FocusMode = Android.Hardware.Camera.Parameters.FocusModeAuto;
}
if (parameters.MaxNumFocusAreas > 0)
{
List<Area> mylist = new List<Area>();
mylist.Add(new Android.Hardware.Camera.Area(focusRect, 1000));
parameters.FocusAreas = mylist;
}
try
{
camera.CancelAutoFocus();
camera.SetParameters(parameters);
camera.StartPreview();
camera.AutoFocus(new AutoFocusCallback());
}
catch (System.Exception ex)
{
Console.WriteLine(ex.ToString());
Console.Write(ex.StackTrace);
}
return true;
}
else
{
return false;
}
}
private Rect CalculateTapArea(object x, object y, float coefficient)
{
var focusAreaSize = Math.Max(textureView.Width, textureView.Height) / 8; //Recommended focus area size from the manufacture is 1/8 of the image
int areaSize = focusAreaSize * (int)coefficient;
int left = clamp(Convert.ToInt32(x) - areaSize / 2, 0, textureView.Width - areaSize);
int top = clamp(Convert.ToInt32(y) - areaSize / 2, 0, textureView.Height - areaSize);
RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);
Matrix.MapRect(rectF);
return new Rect((int)System.Math.Round(rectF.Left), (int)System.Math.Round(rectF.Top), (int)System.Math.Round(rectF.Right), (int)System.Math.Round(rectF.Bottom));
}
private int clamp(int x, int min, int max)
{
if (x > max)
{
return max;
}
if (x < min)
{
return min;
}
return x;
}
public override void Draw(Canvas canvas)
{
base.Draw(canvas);
Paint p = new Paint();
p.Color = Android.Graphics.Color.White;
p.SetStyle(Paint.Style.Stroke);
p.StrokeWidth = 3;
canvas.DrawCircle(300, 300, 100, p);
}
公共类AutoFocusCallback:Java.Lang.Object,IAutoFocusCallback
{
自动对焦上的公共空白(bool success,Android.Hardware.Camera)
{
var参数=camera.GetParameters();
var supportedFocusModes=参数。supportedFocusModes;
if(string.IsNullOrEmpty(parameters.FocusMode))
{
字符串focusModeContinuous=Android.Hardware.Camera.Parameters.FocusModeContinuousPicture;
字符串focusModeAuto=Android.Hardware.Camera.Parameters.focusModeAuto;
if(supportedFocusModes!=null&&supportedFocusModes.Any())
{
if(supportedFocusModes.Contains(focusModeContinuous))
{
parameters.FocusMode=focusModeContinuous;
}
else if(supportedFocusModes.Contains(focusModeAuto))
{
parameters.FocusMode=focusModeAuto;
}
}
}
if(supportedFocusModes!=null&&supportedFocusModes.Any())
{
如果(parameters.MaxNumFocusAreas>0)
{
parameters.focusreas=null;
}
如果(成功)
{
CameraPage CameraPage=新的CameraPage();
画布=新画布();
cameraPage.Draw(画布);
}
设置参数(参数);
camera.StartPreview();
}
}
}
公共bool OnTouch(Android.Views.View v,MotionEvent e)
{
如果(照相机!=null)
{
var参数=camera.GetParameters();
camera.CancelAutoFocus();
Rect focusRect=calculateparea(e.GetX(),e.GetY(),1f);
if(parameters.FocusMode!=Android.Hardware.Camera.parameters.FocusModeAuto)
{
parameters.FocusMode=Android.Hardware.Camera.parameters.FocusModeAuto;
}
如果(parameters.MaxNumFocusAreas>0)
{
名单
这是我的Xamarin.Forms Android应用程序
编辑:这里有一份相机的Android源代码副本,但不确定他们在哪里制作指示器:
没有官方答案的类似SO帖子:
正如你所看到的,很多人都有相同的问题,但没有答案!如果我还不清楚,请告诉我
我已经在下面的点击中实现了自动对焦,但我不确定如何在对焦时绘制圆,并在视图未对焦时将其关闭,以及在相机对焦时继续重新绘制圆
您发布的图片在我看来像是一个系统摄像头,如果使用Intent
启动系统摄像头,我不确定是否可以在系统的摄像头视图上添加一个聚焦圈。但我猜您可能使用了SurfaceView
或TextureView
来自己主持摄像头
如果是这样,对于您的场景,我认为最简单的方法是在布局中放置一个ImageView
,并根据相机焦点状态更改其可见性并重置其LayoutParameters
。例如,图像源必须是透明的。然后我的布局如下所示:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextureView android:id="@+id/textureView"
android:layout_height="match_parent"
android:layout_width="match_parent" />
<Button android:id="@+id/take_photo"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="@string/takephoto" />
<ImageView android:id="@+id/focuscircle"
android:layout_height="80dp"
android:layout_width="80dp"
android:layout_centerInParent="true"
android:src="@drawable/FocusCircle"
android:visibility="invisible" />
</RelativeLayout>
要使其消失,您可以在AutoFocusCallBack
中的success
状态下进行如下编码:
if (success)
{
Task.Delay(1000);
Activity1._focusimg.Visibility = ViewStates.Invisible;
}
为了使ImageView
可以从AutoFocusCallBack
访问,您可以在xamarin中将其设置为静态视图:
private Android.Hardware.Camera _camera;
private TextureView _textureView;
public static ImageView _focusimg;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
_textureView = (TextureView)this.FindViewById(Resource.Id.textureView);
_textureView.SurfaceTextureListener = this;
_textureView.Touch += _textureView_Touch;
var tpBtn = (Button)this.FindViewById(Resource.Id.take_photo);
tpBtn.Click += TpBtn_Click;
_focusimg = (ImageView)this.FindViewById(Resource.Id.focuscircle);
}
每次成功设置焦点时,它都可以正常工作,但我发现有时当我点击TextureView
时,它不会触发\u TextureView\u Touch
事件,我没有深入研究这个问题
另一种方法是在画布上动态画一个圆圈,就像你在代码中所做的那样,它也很有效,但我发现使用这种方法我的演示响应很慢,我也没有深入挖掘这个问题。无论如何,我认为第一种使用图像的方法更简单,如果需要演示,请留下评论。有人能告诉我是什么吗y我不清楚?我正在进一步编辑这个,但我觉得我很清楚。我甚至还添加了一张我想画的视觉指示器的照片。我认为这是一个可以接受的问题,所以人们可以是鸡巴。在我看来,这也很好,非常有效。伟大的人都有同感!我昨天做了和你一样的事情来解决这个问题。我可以分享我的解决方案(尽管可能不如你的准确)。我希望得到反馈。我稍后会分享:)Grace,这部分:“有时当我点击TextureView时,它不会触发_TextureView_Touch事件,我没有深入挖掘这个问题”。你知道为什么会这样吗?@Euridice01,不知道,如果我们将Image
设置为ViewStates。不可见的,它仍然会占用空间,也许我点击了图像…也许我们可以试着将其更改为ViewStates。消失了。
private Android.Hardware.Camera _camera;
private TextureView _textureView;
public static ImageView _focusimg;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
_textureView = (TextureView)this.FindViewById(Resource.Id.textureView);
_textureView.SurfaceTextureListener = this;
_textureView.Touch += _textureView_Touch;
var tpBtn = (Button)this.FindViewById(Resource.Id.take_photo);
tpBtn.Click += TpBtn_Click;
_focusimg = (ImageView)this.FindViewById(Resource.Id.focuscircle);
}