首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么SensorEvent在位图上响应不好,并且有null?

为什么SensorEvent在位图上响应不好,并且有null?
EN

Stack Overflow用户
提问于 2021-09-28 09:42:35
回答 1查看 20关注 0票数 0

我正在做一个应用程序,涉及一个CameraX应用程序接口和位图,我的目标是使相机不仅捕获一个简单的图像,但采取图像和绘制水印文本在图像顶部的文件,但方位,俯仰和滚动显示为空的结果当位图完成,这是它的结果。[![ JPEG文件的实际输出。如果我没有解释正确或者在解释时犯了错误,请尽快让我知道,还有一些问题,我会回答他们。提前谢谢你。

我将赋予图像更多的含义,并将其从保加利亚语翻译成英语,以及它代表什么:倾斜的方位:where(西,南,北,东)方位,倾斜的->:Посока,Наклон

代码语言:javascript
运行
复制
private val mSensorEvent: SensorEvent? = null

override fun onImageSaved(output: ImageCapture.OutputFileResults) {

   //Azimuth, Pitch and Roll
   val azimuthWMText = resources.getString(R.string.value_format_2, mSensorEvent?.values?.get(0))
   val pitchWMText = resources.getString(R.string.value_format_2, mSensorEvent?.values?.get(1))
   val rollWMText = resources.getString(R.string.value_format_2, mSensorEvent?.values?.get(2))

   //Bitmap that contains the addWatermark method and detecting the new photo path that is been taken and implements the watermark
   //BitmapFactory.decodeFile(path.toString(), BitmapFactory.Options()) -> through File
   //resources, R.layout.activity_preview_photo, BitmapFactory.Options() -> through resources
   val originalBitmap = AddWatermark().addWatermark(
                        BitmapFactory.decodeFile(photoFile.toString(), BitmapFactory.Options()),
                        firstWatermarkText = "Дължина: $longitudeWM${resources.getString(R.string.degrees)}, Ширина: $latitudeWM${resources.getString(R.string.degrees)}",
                        secondWatermarkText = "Височина: ${altitudeWM}м, Ориентация: $orientationWM",
                        thirdWatermarkText = "Точност: Хоризонтална: ${hozAccuracyWM}м, Вертикална: ${verAccuracyWM}м",
                        fourthWatermarkText = "Посока: where $azimuthWMText${resources.getString(R.string.degrees)}",
                        fifthWatermarkText = "Наклон: pitchTilt $pitchWMText${resources.getString(R.string.degrees)}, rollTilt $rollWMText${resources.getString(R.string.degrees)}",
                        sixthWatermarkText = "Дата и Час: $dateTimeFormatWMText",
                        AddWatermark.WatermarkOptions(
                            AddWatermark.Corner.TOP_LEFT,
                            textSizeToWidthRation = 0.017f,
                            paddingToWidthRatio = 0.03f,
                            Color.parseColor("#FF0000"),
                            shadowColor = Color.BLACK,
                            strokeOutline = null,
                            typeface = null
                        )
                    )
                    previewView.bitmap.let { originalBitmap }

                    val outputStream = FileOutputStream(photoFile)
                    originalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
                    outputStream.flush()
                    outputStream.close()
                    Toast.makeText(
                        this@CameraActivity,
                        "Обработването и запазено успешно! Запазено е в: $photoFile",
                        Toast.LENGTH_LONG
                    ).show()
}

水印类代码:

代码语言:javascript
运行
复制
class AddWatermark : AppCompatActivity() {
    //Adding watermark method is here for declaring on to the top
    fun addWatermark(
        bitmap: Bitmap,
        firstWatermarkText: String,
        secondWatermarkText: String,
        thirdWatermarkText: String,
        fourthWatermarkText: String,
        fifthWatermarkText: String,
        sixthWatermarkText: String,
        options: WatermarkOptions = WatermarkOptions()): Bitmap {
        val result = bitmap.copy(bitmap.config, true)
        val canvas = Canvas(result)
        val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)
        //val strokePaint = Paint()

        //We are including the Enum class and connecting with the data class WatermarkOptions variable
        paint.textAlign = when (options.corner) {
            //We include the alignment LEFT from Enum class and connecting with Paint variable
            Corner.TOP_LEFT,
            Corner.BOTTOM_LEFT -> Paint.Align.LEFT

            //We include the alignment RIGHT from Enum class and connecting with Paint variable
            Corner.TOP_RIGHT,
            Corner.BOTTOM_RIGHT -> Paint.Align.RIGHT
        }

        /*strokePaint.textAlign = when (options.corner) {
            Corner.TOP_LEFT,
            Corner.BOTTOM_LEFT -> Paint.Align.LEFT

            Corner.TOP_RIGHT,
            Corner.BOTTOM_RIGHT -> Paint.Align.RIGHT
        }

         */

        //We connect the new textSize variable with the bitmap width(default is 0) and we multiply with the WatermarkOption's textSize
        val textSize = result.width * options.textSizeToWidthRation
        //Connecting the Paint textSize variable with the new textSize variable
        paint.textSize = textSize//70.5f
        //Connecting the Paint color variable with the WatermarkOptions textColor
        paint.color = options.textColor
        //If the shadowColor of the WMOptions is not null, then we make it as a Paint shadowLayer variable
        if (options.shadowColor != null) {
            paint.setShadowLayer( 2.5f, 0f, 0f, options.shadowColor)
        }

        /*if (options.strokeOutline != null) {
            strokePaint.textSize = textSize//72f
            strokePaint.color = options.strokeOutline
            strokePaint.style = Paint.Style.STROKE
            strokePaint.strokeWidth = 4.17f
        }

         */

        //If typeface of the WMOptions is not null,we make paint typeface variable and connecting with the WMOptions variable
        if (options.typeface != null) {
            paint.typeface = options.typeface
        }
        //We connect the new padding variable with the bitmap width(default is 0) and multiply with WMOptions padding
        val padding = result.width * options.paddingToWidthRatio

        //Create a variable that has something to do with the coordinates method
        val coordinates = calculateCoordinates(
            firstWatermarkText,
            secondWatermarkText,
            thirdWatermarkText,
            fourthWatermarkText,
            fifthWatermarkText,
            sixthWatermarkText,
            paint,
            options,
            canvas.width,
            canvas.height,
            padding)
        /**drawText text as a Watermark, using Canvas**/
        //canvas.drawText(firstWatermarkText, coordinates.x, coordinates.y, strokePaint)
        //canvas.drawText(secondWatermarkText, coordinates.x, 240f, strokePaint) //We change the Y horizontal coordinates by typing the float number
        //canvas.drawText(thirdWatermarkText, coordinates.x, 310f, strokePaint)
        //canvas.drawText(fourthWatermarkText, coordinates.x, 380f, strokePaint)
        //canvas.drawText(fifthWatermarkText, coordinates.x, 450f, strokePaint)

        when (Build.VERSION.SDK_INT) {
            //Android 11
            30 -> {
                canvas.drawText(firstWatermarkText, coordinates.x, coordinates.y, paint)
                canvas.drawText(secondWatermarkText, coordinates.x, 240f, paint)
                canvas.drawText(thirdWatermarkText, coordinates.x, 310f, paint)
                canvas.drawText(fourthWatermarkText, coordinates.x, 380f, paint)
                canvas.drawText(fifthWatermarkText, coordinates.x, 450f, paint)
                canvas.drawText(sixthWatermarkText, coordinates.x, 520f, paint)
            }

            //Android 9
            28 -> {
                canvas.drawText(firstWatermarkText, coordinates.x, coordinates.y, paint)
                canvas.drawText(secondWatermarkText, coordinates.x, 240f, paint)
                canvas.drawText(thirdWatermarkText, coordinates.x, 310f, paint)
                canvas.drawText(fourthWatermarkText, coordinates.x, 380f, paint)
                canvas.drawText(fifthWatermarkText, coordinates.x, 450f, paint)
                canvas.drawText(sixthWatermarkText, coordinates.x, 520f, paint)
            }

            //Android 5.0
            21 -> {
                canvas.drawText(firstWatermarkText, coordinates.x, coordinates.y, paint)
                canvas.drawText(secondWatermarkText, coordinates.x, 270f, paint)
                canvas.drawText(thirdWatermarkText, coordinates.x, 330f, paint)
                canvas.drawText(fourthWatermarkText, coordinates.x, 420f, paint)
                canvas.drawText(fifthWatermarkText, coordinates.x, 480f, paint)
                canvas.drawText(sixthWatermarkText, coordinates.x, 540f, paint)
            }
        }

        return result
    }

    //This it he corner alignment calculation method and using it on the drawText
    private fun calculateCoordinates(
        firstWatermarkText: String,
        secondWatermarkText: String,
        thirdWatermarkText: String,
        fourthWatermarkText: String,
        fifthWatermarkText: String,
        sixthWatermarkText: String,
        paint: Paint,
        options: WatermarkOptions,
        width: Int,
        height: Int,
        padding: Float
    ): PointF {
        val x = when (options.corner) {
            Corner.TOP_LEFT,
            Corner.BOTTOM_LEFT -> {
                padding
            }
            Corner.TOP_RIGHT,
            Corner.BOTTOM_RIGHT -> {
                width - padding
            }
        }

        val y = when (options.corner) {
            Corner.BOTTOM_LEFT,
            Corner.BOTTOM_RIGHT -> {
                height - padding
            }
            Corner.TOP_LEFT,
            Corner.TOP_RIGHT -> {
                val bounds = Rect()

                paint.getTextBounds(firstWatermarkText, 0, firstWatermarkText.length, bounds)
                paint.getTextBounds(secondWatermarkText, 0, secondWatermarkText.length, bounds)
                paint.getTextBounds(thirdWatermarkText, 0, thirdWatermarkText.length, bounds)
                paint.getTextBounds(fourthWatermarkText, 0, fourthWatermarkText.length, bounds)
                paint.getTextBounds(fifthWatermarkText, 0, fifthWatermarkText.length, bounds)
                paint.getTextBounds(sixthWatermarkText, 0, sixthWatermarkText.length, bounds)

                val textHeight = bounds.height()
                textHeight + padding
            }
        }
        return PointF(x, y)
    }

    enum class Corner {
        TOP_LEFT,
        TOP_RIGHT,
        BOTTOM_LEFT,
        BOTTOM_RIGHT
    }

    data class WatermarkOptions(
        val corner: Corner = Corner.BOTTOM_RIGHT,
        val textSizeToWidthRation: Float = 0.04f,
        val paddingToWidthRatio: Float = 0.03f,
        @ColorInt val textColor: Int = Color.parseColor("#FFC800"),
        @ColorInt val shadowColor: Int? = Color.BLACK,
        @ColorInt val strokeOutline: Int? = Color.BLACK,
        val typeface: Typeface? = null
    )
}
EN

回答 1

Stack Overflow用户

发布于 2021-10-05 13:59:11

好了,我发现了我的问题,我没有使用新的事件,而是使用了“onSensorChanged( mSensorEvent:SensorEvent?)”中的传感器事件。相反,并重新转换所有的lateinit变量,所以这是我问题的答案:

代码语言:javascript
运行
复制
private var azimuthDegree: Double = 0.0
private var currentAzimuth: Double = 0.0

private var currentPitch: Double = 0.0
private var currentRoll: Double = 0.0

//'dirs' is the directions array list of type String and 'currentDirection' will be used for recasting
private var dirs = ArrayList<String>()
private lateinit var currentDirection: String

override fun onResume() {
        super.onResume()
        window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
        actionBar?.hide()

        //Makes a register to the listener about the default sensor for the Azimuth orientation type
        mSensorManager.registerListener(this,
            mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
        SensorManager.SENSOR_DELAY_GAME)
    }

    override fun onPause() {
        super.onPause()

        //If it fails, to unregister the listener from it's sensor
        mSensorManager.unregisterListener(this)
    }

/**The sensor method initializes the type sensors and calculates the gravity and geomagnetic field**/
    @SuppressLint("CutPasteId")
    override fun onSensorChanged(event: SensorEvent?) {
        //Portrait measurements - Correct by default
        try {
            val windowOrientation = windowManager.defaultDisplay.orientation

            //Azimuth
            degreeAzimuth = event!!.values[0].toDouble()
            val azimuthTxt = findViewById<TextView>(R.id.azimuthText)

            //This makes sure that the calculations between Pitch and Roll, doesn't switch places when the orientation is turned between Portrait and Landscape by default
            var degreeRoll: Double
            var degreePitch: Double

            if (windowOrientation == 1 || windowOrientation == 3) {
                degreeRoll = event.values[1].toDouble()
                degreePitch = event.values[2].toDouble()
            } else {
                degreeRoll = event.values[2].toDouble()
                degreePitch = event.values[1].toDouble()
            }

            //Orientation calculations for the Pitch in degrees, when it's Portrait, Landscape, Reverse Portrait and Reverse Landscape, to stay the same case with each and every value
            when (windowOrientation) {
                Surface.ROTATION_0 -> {
                    degreePitch += 90
                }

                1 -> {
                    if (abs(degreeRoll) > 90) {
                        degreePitch -= 90
                        degreeRoll = if (degreeRoll < 0)
                            -(180 + degreeRoll)
                        else
                            180 - degreeRoll
                    } else {
                        degreePitch = 90 - degreePitch
                    }
                }

                2 -> {
                    degreePitch = if (degreePitch < 90)
                        90 - degreePitch
                    else
                        -(degreePitch - 90)
                    degreeRoll = -degreeRoll
                }


                3 -> {
                    if (abs(degreeRoll) > 90) {
                        degreePitch = -(90 + degreePitch)
                        degreeRoll = if (degreeRoll < 0)
                            -(180 + degreeRoll)
                        else
                            180 - degreeRoll
                    } else {
                        degreePitch += 90
                        degreeRoll = -degreeRoll
                    }
                }
            }

            /*Calculations when Azimuth is been turned with a new orientation, that "azimuth"
            is the new variable for making azimuth and window display to be times 90 degrees.
            After that we change the new variable "azimuth" to the dirs array list.*/

//Direction display from the array list from 1 to 9 elements
            val where = findViewById<TextView>(R.id.direction_text)
            dirs = arrayListOf(
                "North",
                "North East",
                "East",
                "South East",
                "South",
                "South West",
                "West",
                "North West",
                "North"
            )

            // We change the "azimuth" variable here, along with it's calculations.
            var azimuth = degreeAzimuth + (windowOrientation * 90)
            when (windowOrientation) {
                //Portrait
                Surface.ROTATION_0 -> {
                    if (azimuth > 360) {
                        azimuth -= 360
                    }
                    azimuthTxt.text = resources.getString(R.string.value_format, azimuth)
                    where.text = dirs[((azimuth + 22.5) / 45.0).toInt()]
                }
                //Landscape
                Surface.ROTATION_90 -> {
                    if (azimuth > 360) {
                        azimuth -= 360
                    }
                    azimuthTxt.text = resources.getString(R.string.value_format, azimuth)
                    where.text = dirs[((azimuth + 22.5) / 45.0).toInt()]
                }
                //Reverse Portrait
                Surface.ROTATION_180 -> {
                    if (azimuth > 360) {
                        azimuth -= 360
                    }
                    azimuthTxt.text = resources.getString(R.string.value_format, azimuth)
                    where.text = dirs[((azimuth + 22.5) / 45.0).toInt()]
                }
                //Reverse Landscape
                Surface.ROTATION_270 -> {
                    if (azimuth > 360) {
                        azimuth -= 360
                    }
                    azimuthTxt.text = resources.getString(R.string.value_format, azimuth)
                    where.text = dirs[((azimuth + 22.5) / 45.0).toInt()]
                }
            }

            currentDirection = dirs[((azimuth + 22.5) / 45.0).toInt()]

            currentAzimuth = azimuth
            val azimuthText = findViewById<TextView>(R.id.azimuthText)
            azimuthText.text = resources.getString(R.string.value_format_2, currentAzimuth)

            currentPitch = degreePitch
            val pitchText = findViewById<TextView>(R.id.pitchText)
            pitchText.text = resources.getString(R.string.value_format, currentPitch)

            currentRoll = degreeRoll
            val rollText = findViewById<TextView>(R.id.rollText)
            rollText.text = resources.getString(R.string.value_format, currentRoll)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

currentAzimuth、currentPith、currentRoll -它们正在重新转换,并将其用作最终结果

azimuthDegree -仅用于计算目的,以适应显示表面的每个方向

另外,由于Sensor.TYPE_ORIENTATION在Java中已被弃用,因此建议的方式如下:

代码语言:javascript
运行
复制
override fun onResume() {
        super.onResume()
        window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
        actionBar?.hide()

        //Makes a register to the listener about the default sensor for the Azimuth gravity and magnetic field
        mSensorManager.registerListener(this,
            mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
        SensorManager.SENSOR_DELAY_GAME)

        mSensorManager.registerListener(this,
            mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
            SensorManager.SENSOR_DELAY_GAME)
    }

    /**The sensor method initializes the type sensors and calculates the gravity and geomagnetic field**/
    @SuppressLint("CutPasteId")
    override fun onSensorChanged(event: SensorEvent?) {
        //Portrait measurements - Correct by default
        try {
            val windowOrientation = windowManager.defaultDisplay.orientation

            //Announcing the alpha for timing
            val alpha = 0.97f
            //The Sensor Event selects a type between Accelerometer and Magnetic Field
            when (event!!.sensor.type) {
                Sensor.TYPE_ACCELEROMETER -> {
                    mGravity[0] = alpha * mGravity[0] + (1 - alpha) * event.values[0]
                    mGravity[1] = alpha * mGravity[1] + (1 - alpha) * event.values[1]
                    mGravity[2] = alpha * mGravity[2] + (1 - alpha) * event.values[2]
                }

                Sensor.TYPE_MAGNETIC_FIELD -> {
                    mGeomagnetic[0] = alpha * mGeomagnetic[0] + (1 - alpha) * event.values[0]
                    mGeomagnetic[1] = alpha * mGeomagnetic[1] + (1 - alpha) * event.values[1]
                    mGeomagnetic[2] = alpha * mGeomagnetic[2] + (1 - alpha) * event.values[2]
                }
            }
            val rotationMatrix = FloatArray(9)
            val inclinationMatrix = FloatArray(9)

            val success: Boolean = SensorManager.getRotationMatrix(rotationMatrix, inclinationMatrix, mGravity, mGeomagnetic)
            
            if (success) {
                //Azimuth
                degreeAzimuth = event!!.values[0].toDouble()
                val azimuthTxt = findViewById<TextView>(R.id.azimuthText)

                //This makes sure that the calculations between Pitch and Roll, doesn't switch places when the orientation is turned between Portrait and Landscape by default
                var degreeRoll: Double
                var degreePitch: Double

                if (windowOrientation == 1 || windowOrientation == 3) {
                    degreeRoll = event.values[1].toDouble()
                    degreePitch = event.values[2].toDouble()
                } else {
                    degreeRoll = event.values[2].toDouble()
                    degreePitch = event.values[1].toDouble()
                }

// We change the "azimuth" variable here, along with it's calculations.
            var azimuth = degreeAzimuth + (windowOrientation * 90)
            when (windowOrientation) {
                //Portrait
                Surface.ROTATION_0 -> {
                    if (azimuth > 360) {
                        azimuth -= 360
                    }
                    azimuthTxt.text = resources.getString(R.string.value_format, azimuth)
                    where.text = dirs[((azimuth + 22.5) / 45.0).toInt()]
                }
                //Landscape
                Surface.ROTATION_90 -> {
                    if (azimuth > 360) {
                        azimuth -= 360
                    }
                    azimuthTxt.text = resources.getString(R.string.value_format, azimuth)
                    where.text = dirs[((azimuth + 22.5) / 45.0).toInt()]
                }
                //Reverse Portrait
                Surface.ROTATION_180 -> {
                    if (azimuth > 360) {
                        azimuth -= 360
                    }
                    azimuthTxt.text = resources.getString(R.string.value_format, azimuth)
                    where.text = dirs[((azimuth + 22.5) / 45.0).toInt()]
                }
                //Reverse Landscape
                Surface.ROTATION_270 -> {
                    if (azimuth > 360) {
                        azimuth -= 360
                    }
                    azimuthTxt.text = resources.getString(R.string.value_format, azimuth)
                    where.text = dirs[((azimuth + 22.5) / 45.0).toInt()]
                }
            }

            currentAzimuth = azimuth
            val azimuthText = findViewById<TextView>(R.id.azimuthText)
            azimuthText.text = resources.getString(R.string.value_format_2, currentAzimuth)

            currentPitch = degreePitch
            val pitchText = findViewById<TextView>(R.id.pitchText)
            pitchText.text = resources.getString(R.string.value_format, currentPitch)

            currentRoll = degreeRoll
            val rollText = findViewById<TextView>(R.id.rollText)
            rollText.text = resources.getString(R.string.value_format, currentRoll)
            }
       }

然后在其中分配AddWatermark类时使用onImageSave()方法,如下所示:

代码语言:javascript
运行
复制
val originalBitmap = AddWatermark().addWatermark(
                            BitmapFactory.decodeFile(photoFile.absolutePath),
                            firstWatermarkText = "Azimuth:$dirs, $currentAzimuth",
                            secondWatermarkText = "Pitch: $currentPitch, Roll: $currentRoll",
                            AddWatermark.WatermarkOptions(
                                AddWatermark.Corner.TOP_LEFT,
                                textSizeToWidthRatio = 0.017f,
                                paddingToWidthRatio = 0.03f,
                                textColor = Color.parseColor("#FF0000"),
                                shadowColor = null,
                                typeface = null
                            )
                        )
                        viewFinder.bitmap.let { originalBitmap }

                        val outputStream = FileOutputStream(photoFile.toString())
                        originalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
                        outputStream.flush()
                        outputStream.close()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69359347

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档