图像金字塔
图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。
图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。
金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。
我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。
高斯金字塔
高斯金字塔的底层为原始图像,每向上一层则是通过高斯滤波和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 BorderTypespublic 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() } }}
效果
高斯金字塔和拉普拉斯金字塔
上面这个拉普拉斯可能看不太清,但是细看是有图像的。让图片宽度充满看看。
为了看清宽度充满
为了看清拉普拉斯金字塔的图像,图片大小本身并非如此
源码
https://github.com/onlyloveyd/LearningAndroidOpenCV
本文分享自微信公众号 - 微卡智享(VaccaeShare)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。