Рисование поверх превью камеры

103
11 августа 2019, 16:40

Хочу вывести превью камеры на дисплей и нарисовать квадрат в области тача. Превью получить удалось, но не могу грамотно реализовать отрисовку. Все время ошибки, плюс иногда получается, что сама графика показывается на несколько секунд и пропадает. Как лучше реализовать это все?

ShowCamera.java

public class ShowCamera extends SurfaceView implements SurfaceHolder.Callback {
Camera camera;
SurfaceHolder holder;
Path path;
volatile boolean running = false;
public ShowCamera(Context context, Camera camera) {
    super(context);
    this.camera = camera;
    holder = getHolder();
    holder.addCallback(this);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    camera.stopPreview();
    camera.release();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
    Camera.Parameters params = camera.getParameters();
    List<Camera.Size> sizes = params.getSupportedPictureSizes();
    Camera.Size mSize = null;
    for(Camera.Size size : sizes){
        mSize = size;
    }
    //change orientation
    if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE){
        params.set("orientation","portrait");
        camera.setDisplayOrientation(90);
        params.setRotation(90);
    }
    else{
        params.set("orientation","landscape");
        camera.setDisplayOrientation(0);
        params.setRotation(0);
    }
    params.setPictureSize(mSize.width,mSize.height);
    camera.setParameters(params);
    try{
        camera.setPreviewDisplay(holder);
        camera.startPreview();
    }
    catch(IOException e){
        e.printStackTrace();
    }
}
}

MainActivity.java

    public class MainActivity extends AppCompatActivity {
    Button btn_run;
    Button btn_select;
    TextView tv;
    FrameLayout camera_preview;
    Camera camera;
    ShowCamera showCamera;
    DrawView drawView;
    float x_touch;
    float y_touch;
    int X_touch;
    int Y_touch;
    String sDown;
    public boolean camera_state = true;
    private boolean onSelect = false;
    private boolean canSelect = false;
    private boolean has_camera = true;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // элементы из activity_main
        btn_run = findViewById(R.id.btn_run);
        btn_select = findViewById(R.id.btn_selectStar);
        camera_preview = findViewById(R.id.camera_preview);
        drawView = findViewById(R.id.drawViewxml);
        tv = findViewById(R.id.tv);
        // проверка на наличие камеры
        if (!checkCameraHardware(MainActivity.this)) {
            has_camera = false;
            Toast toast = Toast.makeText(this, "Камера не найдена", Toast.LENGTH_LONG);
            toast.show();
        }
        // open camera
        camera = Camera.open();
        showCamera = new ShowCamera(this, camera);
        camera_preview.addView(showCamera);
        camera_preview.setVisibility(View.VISIBLE);
        addTouchListener();
    }
    public void btnRunOnClick(View view) {
        if (has_camera) {
            if (camera_state) {
                camera_state = false;
                btn_run.setText("Остановить");
                camera_preview.setVisibility(View.VISIBLE);
                Toast toast = Toast.makeText(this, "Камера остановлена", Toast.LENGTH_SHORT);
                toast.show();
                camera.startPreview();
            } else {
                camera_state = true;
                btn_run.setText("Запустить");
                camera_preview.setVisibility(View.VISIBLE);
                Toast toast = Toast.makeText(this, "Камера запущена", Toast.LENGTH_SHORT);
                toast.show();
                camera.stopPreview();
            }
        } else {
            Toast toast = Toast.makeText(this, "Камера не может быть запущена, \nпоскольку ее нет", Toast.LENGTH_LONG);
            toast.show();
        }
    }
    public void btnSelectStarOnClick(View view) {
        if (onSelect) {
            onSelect = false;
            canSelect = true;
            btn_select.setText("Прекратить");
            Toast toast = Toast.makeText(this, "Выберите объект", Toast.LENGTH_SHORT);
            toast.show();
        } else {
            onSelect = true;
            canSelect = false;
            btn_select.setText("Выбрать");
            Toast toast = Toast.makeText(this, "Выбор запрещен", Toast.LENGTH_SHORT);
            toast.show();
        }
    }

    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            return true;
        } else {
            return false;
        }
    }

    private void addTouchListener(){
        camera_preview.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(canSelect){
                    x_touch = event.getX();
                    y_touch  = event.getY();
                    X_touch = Math.round(x_touch);
                    Y_touch = Math.round(y_touch);
                    sDown = "Down: " + X_touch + "," + Y_touch;
                    tv.setText(sDown);
                }
                return false;
            }
        });
    }
    }
Answer 1

Создайте класс наследник View для прорисовки поверх превью. Этом может быть и тач и фокус и всякие рожки-усики.. Что то типа такого:

public class CameraOverlay extends View{
public CameraOverlay(Context context) {
    super(context);
}
public CameraOverlay(Context context, AttributeSet attrs) {
    super(context, attrs);
}

   @Override
   protected void onDraw(Canvas canvas) {
       super.onDraw(canvas);
      /*тут чето рисуете*/
   }
   @Override
   public boolean onTouchEvent(MotionEvent event) {
      /*улавливаем касание*/
   }

}

Далее класс ViewGroup в котором юзаете камеру и выше созданный класс

public class CameraPreview extends ViewGroup {
   private CameraOverlay overlay;
   private ShowCamera camera;
  public CameraPreview(Context context, AttributeSet attrs) {
    super(context, attrs);
}

}

В разметке получаем такое:

<com.example.CameraPreview
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:id="@+id/preview">
 <com.example.CameraOverlay
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/overlay"/>
</com.example.CameraPreview>

В принципе все.

READ ALSO
Responsive clip-path

Responsive clip-path

В следующем примере блок main (синезелёный градиент) обрезается при помощи clip-path и принимает форму сердечкаОднако видно, что он обрезается...

120
flexbox, текст не переноситься во вложенном flexbox в ie11

flexbox, текст не переноситься во вложенном flexbox в ie11

В IE11 из-за вложенного флексбокса текст не переходит на следующую строку, а растягивается на весь контент, если же поставить дляitem width:100%, блоки...

80
Эффект вождения пальцем по воде

Эффект вождения пальцем по воде

Не знал, как точно сформировать вопрос, поэтому сразу прошу прощения

120
Масштабируемый clipPath

Масштабируемый clipPath

Суть в том, что svg фигура в clipPath отрисовывается как есть, по тем самым размерам, с которыми создана

91