You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin中OpenCV视频角点检测遇Assertion failed错误求解

错误原因及解决方案

错误根源

报错Assertion failed (src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4)的核心原因:

  • Harris角点检测输出类型不兼容:Imgproc.cornerHarris()的输出cornerMat是32位浮点型矩阵(CV_32FC1),但Utils.matToBitmap()仅支持8位单通道/三通道/四通道的Mat,无法直接转换为Bitmap。
  • 额外问题:代码中srcMat初始化为CV_8UC1,但从彩色Bitmap转换而来的Mat实际是CV_8UC3(BGR格式),类型不匹配会导致数据异常。

修复步骤及代码修改

1. 修正Mat初始化类型

  • srcMat:无需提前指定类型,直接用空Mat,Utils.bitmapToMat会自动匹配Bitmap的类型(彩色Bitmap对应CV_8UC3)。
  • cornerMat:初始化为32位浮点型,匹配Harris检测的输出要求。

2. 转换Harris输出为可显示的8位图像

对cornerMat做归一化和类型转换,将浮点值缩放到0-255的8位范围:

  1. 用Core.normalize()将矩阵值归一到0-1区间;
  2. 用Imgproc.convertScaleAbs()将归一化后的浮点值转换为8位无符号整数(CV_8UC1)。

3. 其他代码优化

  • 处理frameNum为空的边界情况;
  • 控制循环帧率,避免处理速度过快;
  • 及时释放Mat资源,防止内存泄漏;
  • 避免重复复用同一个Bitmap对象,创建新Bitmap用于显示结果。

修改后的完整代码

class MainActivity : AppCompatActivity() {

    @RequiresApi(Build.VERSION_CODES.P)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 初始化OpenCV,建议放在Application中避免重复初始化
        if (!OpenCVLoader.initDebug()) {
            Log.e("OpenCV", "初始化失败")
            return
        }

        val videoView = findViewById<VideoView>(R.id.videoView)
        val imgView = findViewById<ImageView>(R.id.imageView)

        val uri = Uri.parse("android.resource://" + packageName + "/" + R.raw.video_name)
        videoView.setVideoURI(uri)
        videoView.start()

        val retriever = MediaMetadataRetriever()
        val context = applicationContext
        retriever.setDataSource(context, uri)

        val frameNumStr = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT)
        val frameNum = frameNumStr?.toInt() ?: run {
            Log.e("VideoFrame", "无法获取视频帧数")
            return@onCreate
        }

        thread {
            try {
                // 复用Mat,减少内存开销
                val srcMat = Mat()
                val grayMat = Mat()
                val cornerMat = Mat()
                val normalizedMat = Mat()
                val displayMat = Mat()

                // 假设视频帧率为30fps,控制每帧处理间隔
                val frameDelay = (1000 / 30).toLong()

                for (i in 0 until frameNum) {
                    val bitframe = retriever.getFrameAtIndex(i) ?: continue
                    val f_width = bitframe.width
                    val f_height = bitframe.height

                    // Bitmap转Mat,自动匹配类型
                    Utils.bitmapToMat(bitframe, srcMat)
                    // 灰度化
                    Imgproc.cvtColor(srcMat, grayMat, Imgproc.COLOR_BGR2GRAY)

                    // Harris角点检测,输出为CV_32FC1
                    Imgproc.cornerHarris(grayMat, cornerMat, 3, 5, 0.04)

                    // 归一化到0-1范围
                    Core.normalize(cornerMat, normalizedMat, 0.0, 1.0, Core.NORM_MINMAX)
                    // 转换为8位无符号整数(CV_8UC1)
                    Imgproc.convertScaleAbs(normalizedMat, displayMat)

                    // 创建新Bitmap用于显示结果,避免覆盖原帧Bitmap
                    val resultBitmap = Bitmap.createBitmap(f_width, f_height, Bitmap.Config.ARGB_8888)
                    Utils.matToBitmap(displayMat, resultBitmap)

                    // 更新UI
                    Handler(Looper.getMainLooper()).post {
                        imgView.setImageBitmap(resultBitmap)
                    }

                    // 控制帧率,避免处理过快
                    Thread.sleep(frameDelay)
                }

                // 释放Mat资源
                srcMat.release()
                grayMat.release()
                cornerMat.release()
                normalizedMat.release()
                displayMat.release()
                retriever.release()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}

关键修改点说明

  • Mat类型匹配:cornerMat初始化为CV_32FC1,符合Harris检测的输出要求;
  • 归一化与类型转换:通过Core.normalize()和Imgproc.convertScaleAbs()将浮点矩阵转为可显示的8位图像;
  • 内存优化:复用Mat对象,避免循环中频繁创建;
  • 帧率控制:添加Thread.sleep()使处理速度与视频帧率匹配;
  • 边界处理:增加对frameNum和bitframe为空的判断,避免空指针异常。

内容的提问来源于stack exchange,提问作者y_ok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 22:54:32