質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Atmel Studio

Atmel Studioは、マイクロチップ・テクノロジー社が製造しているマイコンであるAVRやSAMのプログラミングを容易にするための統合開発環境です。同社が無料で提供しており、以前はAVR Studioと呼ばれていました。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

1回答

5835閲覧

[Android] CameraXでキャプチャした写真が90°回転してしまう

CAIOS

総合スコア24

Atmel Studio

Atmel Studioは、マイクロチップ・テクノロジー社が製造しているマイコンであるAVRやSAMのプログラミングを容易にするための統合開発環境です。同社が無料で提供しており、以前はAVR Studioと呼ばれていました。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2020/01/09 14:27

###問題
CameraXを使用してカメラアプリを作っているのですが、takePictureでキャプチャした写真が90°回転してしまいます。

毎回回転してしまうわけではなく、横画面時(TextureView.display.rotationが1,3の時)は回転せず、ちゃんとキャプチャできています。

しかし、縦画面時(TextureView.display.rotationが0,2)のときは下図のように横長で90°回転した写真をキャプチャしてしまいます。

ImageCapture.setTargetRotationで回転を指定しても何も変わりませんでした。

Googleのこのサンプルを参考にしながらアプリを作成したのですが、Googleのサンプルのキャプチャ後の写真は正しい回転をしています。サンプルをほぼなぞるようにして書いたので、何が違い、何が原因で回転してしまうのか全く分かりません。

何かわかる方がいましたらご回答お願いします。

###写真
縦画面時に撮影した写真
90°回転してしまっています。
イメージ説明

###コード

Kotlin

1package caios.android.camera_x_sample 2 3 4import android.content.ContentValues 5import android.content.Context 6import android.content.res.Configuration 7import android.hardware.camera2.CameraManager 8import android.hardware.display.DisplayManager 9import androidx.camera.core.ImageCapture.Metadata 10import android.os.Bundle 11import android.os.Environment 12import android.os.Message 13import android.provider.MediaStore 14import android.util.DisplayMetrics 15import androidx.fragment.app.Fragment 16import android.view.LayoutInflater 17import android.view.TextureView 18import android.view.View 19import android.view.ViewGroup 20import android.widget.Button 21import android.widget.Toast 22import androidx.appcompat.app.AppCompatActivity 23import androidx.camera.core.* 24import androidx.constraintlayout.widget.ConstraintLayout 25import androidx.core.app.ActivityCompat 26import androidx.core.content.ContextCompat 27import java.io.File 28import java.util.concurrent.Executor 29import kotlin.math.abs 30import kotlin.math.max 31import kotlin.math.min 32 33class CameraFragment : Fragment(), View.OnClickListener { 34 35 private lateinit var callerContext: Context 36 private lateinit var callerActivity: AppCompatActivity 37 38 private lateinit var rootLayout: ConstraintLayout 39 private lateinit var textureView: TextureView 40 41 private lateinit var cameramanager: CameraManager 42 private lateinit var displayManager: DisplayManager 43 44 private lateinit var preview: Preview 45 private lateinit var imageCapture: ImageCapture 46 47 private lateinit var mainExecutor: Executor 48 49 private var cameraFacing = CameraX.LensFacing.BACK 50 private var displayId = 0 51 52 private val displayListener = object : DisplayManager.DisplayListener{ 53 override fun onDisplayAdded(id: Int) = Unit 54 override fun onDisplayRemoved(id: Int) = Unit 55 override fun onDisplayChanged(id: Int) = view?.let {view -> 56 if(this@CameraFragment.displayId == id){ 57 preview.setTargetRotation(view.display.rotation) 58 imageCapture.setTargetRotation(view.display.rotation) 59 } 60 } ?:Unit 61 } 62 63 override fun onAttach(context: Context) { 64 super.onAttach(context) 65 callerContext = context 66 callerActivity = context as AppCompatActivity 67 } 68 69 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 70 return inflater.inflate(R.layout.fragment_camera, container, false) 71 } 72 73 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 74 super.onViewCreated(view, savedInstanceState) 75 76 rootLayout = view as ConstraintLayout 77 textureView = rootLayout.findViewById(R.id.FC_TextureView) 78 79 rootLayout.systemUiVisibility = FLAGS_FULLSCREEN 80 81 cameramanager = callerContext.getSystemService(Context.CAMERA_SERVICE) as CameraManager 82 83 displayManager = callerActivity.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager 84 displayManager.registerDisplayListener(displayListener, null) 85 86 mainExecutor = ContextCompat.getMainExecutor(requireContext()) 87 88 textureView.post { 89 displayId = textureView.display.displayId 90 updateUI() 91 startCameraX() 92 } 93 } 94 95 override fun onResume() { 96 super.onResume() 97 if (::rootLayout.isInitialized) rootLayout.systemUiVisibility = FLAGS_FULLSCREEN 98 displayManager.registerDisplayListener(displayListener, null) 99 } 100 101 override fun onPause() { 102 super.onPause() 103 displayManager.unregisterDisplayListener(displayListener) 104 } 105 106 override fun onConfigurationChanged(newConfig: Configuration) { 107 super.onConfigurationChanged(newConfig) 108 updateUI() 109 } 110 111 override fun onClick(view: View?) { 112 when(view?.id){ 113 R.id.CU_Capture -> takePicture() 114 } 115 } 116 117 private fun startCameraX(){ 118 val matrix = DisplayMetrics().also { textureView.display.getRealMetrics(it) } 119 val screenAspectRatio = aspectRatio(matrix.widthPixels, matrix.heightPixels) 120 121 val previewConfig = PreviewConfig.Builder().apply { 122 setLensFacing(cameraFacing) 123 setTargetAspectRatio(screenAspectRatio) 124 setTargetRotation(textureView.display.rotation) 125 }.build() 126 127 val imageCaptureConfig = ImageCaptureConfig.Builder().apply { 128 setLensFacing(cameraFacing) 129 setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY) 130 setFlashMode(FlashMode.AUTO) 131 setTargetAspectRatio(screenAspectRatio) 132 setTargetRotation(textureView.display.rotation) 133 }.build() 134 135 preview = AutoFitPreviewBuilder.build(previewConfig, textureView) 136 imageCapture = ImageCapture(imageCaptureConfig) 137 138 CameraX.bindToLifecycle(viewLifecycleOwner, preview, imageCapture) 139 } 140 141 private fun updateUI(){ 142 rootLayout.findViewById<ConstraintLayout>(R.id.CU_RootView)?.let { 143 rootLayout.removeView(it) 144 } 145 146 val controls = View.inflate(requireContext(), R.layout.camera_ui, rootLayout) 147 148 controls.findViewById<Button>(R.id.CU_Capture).setOnClickListener(this) 149 } 150 151 private fun takePicture(){ 152 imageCapture.let {imageCapture -> 153 val fileName = System.currentTimeMillis().toString() + ".JPG" 154 val imageFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), fileName) 155 val metaData = Metadata().apply { 156 isReversedHorizontal = (cameraFacing == CameraX.LensFacing.FRONT) 157 } 158 val imageSavedListener = object : ImageCapture.OnImageSavedListener { 159 override fun onImageSaved(file: File) { 160 toast("Capture Success\n${file.absolutePath}") 161 reloadPictures(file) 162 } 163 164 override fun onError(imageCaptureError: ImageCapture.ImageCaptureError, message: String, cause: Throwable?) = toast("Capture Error\n$message") 165 } 166 167 imageCapture.takePicture(imageFile, metaData, mainExecutor, imageSavedListener) 168 } 169 } 170 171 private fun reloadPictures(file: File){ 172 val contentValue = ContentValues().apply { 173 put(MediaStore.Images.Media.MIME_TYPE, "image/JPG") 174 put("_data", file.absolutePath) 175 } 176 177 callerContext.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValue) 178 } 179 180 private fun aspectRatio(width: Int, height: Int): AspectRatio { 181 val previewRatio = max(width, height).toDouble() / min(width, height) 182 183 if (abs(previewRatio - ASPECT_RATIO_4_3) <= abs(previewRatio - ASPECT_RATIO_16_9)) { 184 return AspectRatio.RATIO_4_3 185 } 186 return AspectRatio.RATIO_16_9 187 } 188 189 private fun toast(message: String) = Toast.makeText(callerContext, message, Toast.LENGTH_SHORT).show() 190 191 companion object{ 192 const val ASPECT_RATIO_4_3 = 4.0 / 3.0 193 const val ASPECT_RATIO_16_9 = 16.0 / 9.0 194 const val MAX_PREVIEW_WIDTH = 1920 195 const val MAX_PREVIEW_HEIGHT = 1080 196 const val FLAGS_FULLSCREEN = View.SYSTEM_UI_FLAG_LOW_PROFILE or 197 View.SYSTEM_UI_FLAG_FULLSCREEN or 198 View.SYSTEM_UI_FLAG_LAYOUT_STABLE or 199 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or 200 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or 201 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 202 } 203}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

JPGデータのヘッダ部に、画像の方向の情報が格納されてます。
画像を表示する際には、その情報をもとに画像を回転してやらなければなりません

投稿2020/01/09 15:16

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

CAIOS

2020/01/10 03:59

ご回答ありがとうございます。 ちなみにGoogleのサンプルで言うとその処理はどのあたりになるのでしょうか...?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問