Android基于OpenCV实现图像金字塔

 更新时间:2021年06月18日 10:08:31   作者:易冬  
图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。本文讲解Android基于OpenCV实现图像金字塔的步骤

图像金字塔

图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。

图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。

金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。

我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

高斯金字塔

高斯金字塔的底层为原始图像,每向上一层则是通过高斯滤波和1/2采样得到(去掉偶数行和列)。通过下采样不断的将图像的尺寸缩小,进而在金字塔中包含多个尺度的图像,一般情况下,高斯金字塔的最底层为图像的原图,每上一层就会通过下采样缩小一次图像的尺寸,通常情况尺寸会缩小为原来的一半,但是如果有特殊需求,缩小的尺寸也可以根据实际情况进行调整。由于每次图像的尺寸都缩小为原来的一半,图像尺缩小的速度非常快,因此常见高斯金字塔的层数为3到6层。

高斯滤波器可以看做一个低通滤波器,那么每经过一次的高斯滤波,图像中仅能够保留某个频率值以下的频率部分,所以高斯金字塔也可以看做一个低通金字塔(每一级只保留某个频率以下的成分)。

拉普拉斯金字塔

拉普拉斯金字塔与高斯金字塔正好相反,高斯金字塔通过底层图像构建上层图像,而拉普拉斯是通过上层小尺寸的图像构建下层大尺寸的图像。拉普拉斯金字塔具有预测残差的作用,需要与高斯金字塔联合一起使用,假设我们已经有一个高斯图像金字塔,对于其中的第i层图像(高斯金字塔最下面为第0层),首先通过下采样得到一尺寸缩小一半的图像,即高斯金字塔中的第i+1层或者不在高斯金字塔中,之后对这张图像再进行上采样,将图像尺寸恢复到第i层图像的大小,最后求取高斯金字塔第i层图像与经过上采样后得到的图像的差值图像,这个差值图像就是拉普拉斯金字塔的第i层图像。

API

下采样

public static void pyrDown(Mat src, Mat dst, Size dstsize, int borderType) 
  • 参数一:src,输入待下采样的图像。
  • 参数二:dst,输出下采样后的图像,图像尺寸可以指定,但是数据类型和通道数与src相同,
  • 参数三:dstsize,输出图像尺寸,可以缺省。
  • 参数四:borderType,像素边界外推方法的标志
// C++: enum BorderTypes
public static final int
        BORDER_CONSTANT = 0,
        BORDER_REPLICATE = 1,
        BORDER_REFLECT = 2,
        BORDER_WRAP = 3,
        BORDER_REFLECT_101 = 4,
        BORDER_TRANSPARENT = 5,
        BORDER_REFLECT101 = BORDER_REFLECT_101,
        BORDER_DEFAULT = BORDER_REFLECT_101,
        BORDER_ISOLATED = 16;

默认状态下函数输出的图像的尺寸为输入图像尺寸的一半,但是也可以通过dstsize参数来设置输出图像的大小,需要注意的是无论输出尺寸为多少都应满足下面式中条件。该函数首先将原图像与内核矩阵进行卷积,内核矩阵如下所示,之后通过不使用偶数行和列的方式对图像进行下采样,最终实现尺寸缩小的下采样图像。

上采样

public static void pyrUp(Mat src, Mat dst, Size dstsize, int borderType) 
  • 参数一:src,输入待上采样的图像。
  • 参数二:dst,输出上采样后的图像,图像尺寸可以指定,但是数据类型和通道数与src相同,
  • 参数三:dstsize,输出图像尺寸,可以缺省。
  • 参数四:borderType,像素边界外推方法的标志

操作

class GLPyramidActivity : CardGalleryActivity() {

    override fun buildCards() {
        val bgr = Utils.loadResource(this, R.drawable.lena)
        val rgb = Mat()
        Imgproc.cvtColor(bgr, rgb, Imgproc.COLOR_BGR2RGB)
        bgr.release()
        buildGauss(rgb)
        rgb.release()
    }

    private fun buildGauss(source: Mat) {
        val gaussList = arrayListOf<Mat>()
        gaussList.add(source)
        for (i in 0..2) {
            val gauss = Mat()
            Imgproc.pyrDown(gaussList[i], gauss)
            gaussList.add(gauss)
        }

        for (i in gaussList.indices) {
            val bitmap = Bitmap.createBitmap(
                gaussList[i].width(),
                gaussList[i].height(),
                Bitmap.Config.ARGB_8888
            )
            Utils.matToBitmap(gaussList[i], bitmap)
            cards.add(Card("Gauss${i}", bitmap))
        }
        buildLaplace(gaussList)
    }

    private fun buildLaplace(gaussList: List<Mat>) {
        val laplaceList = arrayListOf<Mat>()
        for (i in gaussList.size - 1 downTo 1) {
            val lap = Mat()
            val upGauss = Mat()
            if (i == gaussList.size - 1) {
                val down = Mat()
                Imgproc.pyrDown(gaussList[i], down)
                Imgproc.pyrUp(down, upGauss)
                Core.subtract(gaussList[i], upGauss, lap)
                laplaceList.add(lap.clone())
            }
            Imgproc.pyrUp(gaussList[i], upGauss)
            Core.subtract(gaussList[i - 1], upGauss, lap)
            laplaceList.add(lap.clone())
        }

        for (i in laplaceList.indices) {
            val bitmap = Bitmap.createBitmap(
                laplaceList[i].width(),
                laplaceList[i].height(),
                Bitmap.Config.ARGB_8888
            )
            Utils.matToBitmap(laplaceList[i], bitmap)
            cards.add(Card("Laplace${i}", bitmap))
        }

        for (gauss in gaussList) {
            gauss.release()
        }
        for (lap in laplaceList) {
            lap.release()
        }
    }
}

操作

class GLPyramidActivity : CardGalleryActivity() {

    override fun buildCards() {
        val bgr = Utils.loadResource(this, R.drawable.lena)
        val rgb = Mat()
        Imgproc.cvtColor(bgr, rgb, Imgproc.COLOR_BGR2RGB)
        bgr.release()
        buildGauss(rgb)
        rgb.release()
    }

    private fun buildGauss(source: Mat) {
        val gaussList = arrayListOf<Mat>()
        gaussList.add(source)
        for (i in 0..2) {
            val gauss = Mat()
            Imgproc.pyrDown(gaussList[i], gauss)
            gaussList.add(gauss)
        }

        for (i in gaussList.indices) {
            val bitmap = Bitmap.createBitmap(
                gaussList[i].width(),
                gaussList[i].height(),
                Bitmap.Config.ARGB_8888
            )
            Utils.matToBitmap(gaussList[i], bitmap)
            cards.add(Card("Gauss${i}", bitmap))
        }
        buildLaplace(gaussList)
    }

    private fun buildLaplace(gaussList: List<Mat>) {
        val laplaceList = arrayListOf<Mat>()
        for (i in gaussList.size - 1 downTo 1) {
            val lap = Mat()
            val upGauss = Mat()
            if (i == gaussList.size - 1) {
                val down = Mat()
                Imgproc.pyrDown(gaussList[i], down)
                Imgproc.pyrUp(down, upGauss)
                Core.subtract(gaussList[i], upGauss, lap)
                laplaceList.add(lap.clone())
            }
            Imgproc.pyrUp(gaussList[i], upGauss)
            Core.subtract(gaussList[i - 1], upGauss, lap)
            laplaceList.add(lap.clone())
        }

        for (i in laplaceList.indices) {
            val bitmap = Bitmap.createBitmap(
                laplaceList[i].width(),
                laplaceList[i].height(),
                Bitmap.Config.ARGB_8888
            )
            Utils.matToBitmap(laplaceList[i], bitmap)
            cards.add(Card("Laplace${i}", bitmap))
        }

        for (gauss in gaussList) {
            gauss.release()
        }
        for (lap in laplaceList) {
            lap.release()
        }
    }
}

效果

上面这个拉普拉斯可能看不太清,但是细看是有图像的。让图片宽度充满看看。

为了看清拉普拉斯金字塔的图像,图片大小本身并非如此

源码

github.com/onlyloveyd/…

以上就是Android基于OpenCV实现图像金字塔的详细内容,更多关于Android OpenCV图像金字塔的资料请关注脚本之家其它相关文章!

相关文章

最新评论