图像分割(均值漂移)
onlyloveyd 200 4

图像分割

图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。它是由图像处理到图像分析的关键步骤。现有的图像分割方法主要分以下几类:基于阈值的分割方法、基于区域的分割方法、基于边缘的分割方法以及基于特定理论的分割方法等。从数学角度来看,图像分割是将数字图像划分成互不相交的区域的过程。图像分割的过程也是一个标记过程,即把属于同一区域的像素赋予相同的编号。

均值漂移(Mean-Shift)

MeanShfit 均值漂移算法是一种通用的聚类算法,通常可以实现彩色图像分割。

基本思想为:首先随便选择一个中心点,然后计算该中心点一定范围之内所有点到中心点的距离向量的平均值,计算该平均值得到一个偏移均值,然后将中心点移动到偏移均值位置,通过这种不断重复的移动,可以使中心点逐步逼近到最佳位置。这种思想类似于梯度下降方法,通过不断的往梯度下降的方向移动,可以到达梯度上的局部最优解或全局最优解。

算法原理参考:https://www.biaodianfu.com/mean-shift.html#Mean_Shift%E7%AE%97%E6%B3%95%E7%90%86%E8%AE%BA

图像分割(均值漂移)

图像分割(均值漂移)

API

pyrMeanShiftFiltering函数其实也是一种滤波,只能达到平滑图像的效果,无法直接分割图像。但是平滑后的图像更方便我们进行图像分割。

public static void pyrMeanShiftFiltering(Mat src, Mat dst, double sp, double sr, int maxLevel, TermCriteria termcrit)
  • 参数一:src,输入图像,类型为8位三通道。
  • 参数二:dst,输出图像,与src大小类型相同。
  • 参数三:sp,漂移的物理空间半径大小。
  • 参数四:sr,漂移的颜色空间半径大小。
  • 参数五:maxLevel,用于分割的金字塔的最大级别。
  • 参数六:termcrit,终止标准:何时停止均值漂移迭代。

sp,sr越大,平滑效果越明显,处理时间越长

操作

由于Mean-Shift均值漂移无法直接分割图像,我们配合漫水填充法执行分割操作。

/**
 * Mean-Shift 均值漂移
 *
 * @author yidong
 * @date 11/25/20
 */
class MeanShiftActivity : AppCompatActivity() {

    private val mBinding: ActivityMeanShiftBinding by lazy {
        ActivityMeanShiftBinding.inflate(layoutInflater)
    }
    private lateinit var mRgb: Mat

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(mBinding.root)
        mRgb = Mat()
        val bgr = Utils.loadResource(this, R.drawable.number)
        Imgproc.cvtColor(bgr, mRgb, Imgproc.COLOR_BGR2RGB)
        mBinding.ivLena.showMat(mRgb)
        mBinding.isLoading = true
        GlobalScope.launch(Dispatchers.IO) {
            doMeanShift()
        }
    }

    private fun doMeanShift() {
        val dst = Mat()
        Imgproc.pyrMeanShiftFiltering(mRgb, dst, 40.0, 40.0)

        val maskers = Mat(dst.rows() + 2, dst.cols() + 2, CvType.CV_8UC1, Scalar.all(0.0))
        Imgproc.floodFill(
            dst,
            maskers,
            Point(7.0, 7.0),
            Scalar(65.0, 105.0, 225.0),
            Rect(),
            Scalar.all(10.0),
            Scalar.all(10.0),
            Imgproc.LINE_4 or Imgproc.FLOODFILL_FIXED_RANGE or (250 shl 8)
        )

        GlobalScope.launch(Dispatchers.Main) {
            mBinding.isLoading = false
            mBinding.ivResult.showMat(dst)
        }
    }
}

效果

图像分割(均值漂移)

源码

https://github.com/onlyloveyd/LearningAndroidOpenCV

评论区

索引目录