■ UI
■ ソースコード
●MainActivity.java
java MainActivity.java
package com.example.camera_x_001;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.CameraX;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageAnalysisConfig;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureConfig;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.core.PreviewConfig;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.media.Image;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.common.util.concurrent.ListenableFuture;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
// 定数
private final int REQUEST_CODE_PERMISSIONS = 101;
// UI
private TextureView textureView;
private Button captureButton, opne_button, capture_button;
private TextView get_with, get_height, get_gyouretu;
private String str_get_with, str_get_height;
// === ピンチアウト用
private ScaleGestureDetector scaleGestureDetector;
private float scaleFactor = 0.05f;
private int test_count = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
textureView = findViewById(R.id.texture_view);
// scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
/**
* === カメラ起動 ===
*/
opne_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// カメラ 起動
startCamera();
}
});
} // === END onCreate
/**
* === カメラ 画面タッチ イベント ===
*/
/*
@Override
public boolean onTouchEvent(MotionEvent event) {
scaleGestureDetector.onTouchEvent(event);
return true;
}
*/
/**
* === カメラ 画面タッチ イベント ===
*/
/*
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
// 最小・最大スケールを制限する場合は、適宜設定
scaleFactor = Math.max(0.01f, Math.min(scaleFactor, 2.0f));
// TextureViewのサイズを更新する
int width = (int) (textureView.getWidth() * scaleFactor);
int height = (int) (textureView.getHeight() * scaleFactor);
textureView.setLayoutParams(new FrameLayout.LayoutParams(width, height));
return true;
}
}
*/
/**
* ========= カメラの開始 =========
*/
private void startCamera() {
// プレビューの表示
PreviewConfig pConfig = new PreviewConfig.Builder().build();
Preview preview = new Preview(pConfig);
preview.setOnPreviewOutputUpdateListener(
output -> {
// SurfaceTextureの更新
ViewGroup parent = (ViewGroup)this.textureView.getParent();
parent.removeView(this.textureView);
parent.addView(this.textureView, 0);
// SurfaceTextureをTextureViewに指定
this.textureView.setSurfaceTexture(output.getSurfaceTexture());
// TextureViewのサイズの調整
int w = output.getTextureSize().getWidth();
int h = output.getTextureSize().getHeight();
int degree = output.getRotationDegrees();
if (degree == 90 || degree == 270) {
w = output.getTextureSize().getHeight();
h = output.getTextureSize().getWidth();
}
h = h * textureView.getWidth() / w;
w = textureView.getWidth();
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(w,h);
params.startToStart = ConstraintLayout.LayoutParams.PARENT_ID;
params.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID;
params.topToTop = ConstraintLayout.LayoutParams.PARENT_ID;
params.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID;
textureView.setLayoutParams(params);;
});
/**
* ========= 画像の解析 =========
*/
ImageAnalysisConfig config = new ImageAnalysisConfig.Builder()
.setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
.build();
ImageAnalysis imageAnalysis = new ImageAnalysis(config);
imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(),
new ImageAnalysis.Analyzer() {
@Override
public void analyze(ImageProxy image, int rotationDegrees) {
// === 横 、縦 取得
str_get_with = String.valueOf(image.getWidth() * test_count);
str_get_height = String.valueOf(image.getHeight() * test_count);
// === 表示行列 取得
Matrix transformMatrix = new Matrix();
String Tmp_Matrix = String.valueOf(textureView.getTransform(transformMatrix));
runOnUiThread(new Runnable() {
@Override
public void run() {
get_with.setText(str_get_with); // 横
get_height.setText(str_get_height); // 縦
get_gyouretu.setText(Tmp_Matrix); // 表示行列
}
});
android.util.Log.d("出力:::analyze:::",+image.getWidth()+"x"+image.getHeight());
android.util.Log.d("出力:::analyze:::",Tmp_Matrix);
test_count++;
}
});
/**
* ========= 画像のキャプチャ =========
*/
ImageCaptureConfig cConfig = new ImageCaptureConfig.Builder()
.setTargetRotation(getWindowManager().getDefaultDisplay().getRotation())
.build();
ImageCapture imageCapture = new ImageCapture(cConfig);
// ボタンのイベントリスナー
captureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 画像のキャプチャ
File file = new File(getFilesDir(), "captured.jpg");
imageCapture.takePicture(file, Executors.newSingleThreadExecutor(),
new ImageCapture.OnImageSavedListener() {
// 成功時に呼ばれる
@Override
public void onImageSaved(File file) {
android.util.Log.d("debug","success フォト保存OKOKOK");
}
// エラー時に呼ばれる
@Override
public void onError(
ImageCapture.ImageCaptureError imageCaptureError,
String message, Throwable cause) {
android.util.Log.d("debug","error");
}
});
}
});
// カメラのライフサイクルのバインド
// CameraX.bindToLifecycle(this, imageAnalysis,preview);
CameraX.bindToLifecycle(this, imageCapture, imageAnalysis, preview);
}
private void init() {
captureButton = findViewById(R.id.capture_button); // 画面キャプチャ
opne_button = findViewById(R.id.opne_button); // カメラ起動
get_with = findViewById(R.id.get_with); // 横
get_height = findViewById(R.id.get_height); // 縦
get_gyouretu = findViewById(R.id.get_gyouretu); // 表示行列
}
}
●activity_main.xml
xml activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/get_with"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12dp"
android:textColor="#000"
android:text="横:"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
/>
<TextView
android:id="@+id/get_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12dp"
android:textColor="#000"
android:text="縦:"
app:layout_constraintTop_toBottomOf="@+id/get_with"
app:layout_constraintLeft_toLeftOf="parent"
/>
<TextView
android:id="@+id/get_gyouretu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12dp"
android:textColor="#000"
android:text="表示行列:"
app:layout_constraintTop_toBottomOf="@+id/get_height"
app:layout_constraintLeft_toLeftOf="parent"
/>
<TextureView
android:id="@+id/texture_view"
android:layout_width="540px"
android:layout_height="540px"
app:layout_constraintTop_toBottomOf="@+id/get_gyouretu"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<Button
android:id="@+id/opne_button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="カメラ起動"
android:layout_marginTop="22dp"
android:layout_marginBottom="22dp"
app:layout_constraintTop_toBottomOf="@+id/texture_view"
app:layout_constraintRight_toLeftOf="@+id/capture_button"
app:layout_constraintLeft_toLeftOf="parent"
/>
<Button
android:id="@+id/capture_button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="撮影"
android:layout_marginTop="22dp"
android:layout_marginBottom="22dp"
app:layout_constraintTop_toBottomOf="@+id/texture_view"
app:layout_constraintLeft_toRightOf="@+id/opne_button"
app:layout_constraintRight_toRightOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
●AndroidManifest.xml
xml AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- パーミッション 追加 -->
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Camera_x_001"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
●build.gradle(Module:app)
plugins {
id 'com.android.application'
}
android {
namespace 'com.example.camera_x_001'
compileSdk 33
defaultConfig {
applicationId "com.example.camera_x_001"
minSdk 25
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation project(path: ':sdk')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
// === モジュール 追加 ===
// def camerax_version = "1.0.0-beta03"
def camerax_version = '1.0.0-alpha06'
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-core:${camerax_version}"
}