Android OpenCV(三十八):凸包检测

凸包

凸包(Convex Hull)是一个计算几何(图形学)中的概念。在一个实数向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包。X的凸包可以用X内所有点(X1,…Xn)的凸组合来构造.
在二维欧几里得空间中,凸包可想象为一条刚好包着所有点的橡皮圈
用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。

凸包

凸包缺陷

凸包缺陷

如图所示,黑色的轮廓线为convexity hull(凸包),而convexity hull(凸包)与手掌之间的部分为convexity defects(凸包缺陷).

API

public static void convexHull(MatOfPoint points, MatOfInt hull, boolean clockwise) 
  • 参数一:points,输入的二维点集。
  • 参数二:hull,输出凸包点索引集合。索引指的是第一个参数中二维点集的索引。
  • 参数三:clockwise,方向标志位。true时,凸包顺序为顺时针方向;false时,凸包顺序为逆时针方向。
public static void convexityDefects(MatOfPoint contour, MatOfInt convexhull, MatOfInt4 convexityDefects)
  • 参数一:contour,输入的轮廓。
  • 参数二:convexhull,上面convexHull方法的输出结果hull。
  • 参数三:convexityDefects,凸包缺陷特征集合。每个convexity defect区域有四个特征量:起始点(startPoint),结束点(endPoint),距离convexity hull最远点(farPoint),最远点到convexity hull的距离(depth)。

算法

[217] Jack Sklansky. Finding the convex hull of a simple polygon. Pattern Recognition Letters, 1(2):79–83, 1982.

操作

/**
 * 凸包检测,凸包缺陷
 *
 * @author yidong
 * @date 2020/10/13
 */
class ConvexHullActivity : AppCompatActivity() {

    private lateinit var mBinding: ActivityConvexHullBinding
    private lateinit var mSource: Mat
    private lateinit var mGray: Mat


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_convex_hull)
        val bgr = Utils.loadResource(this, R.drawable.star)
        mSource = Mat()
        mGray = Mat()

        Imgproc.cvtColor(bgr, mGray, Imgproc.COLOR_BGR2GRAY)
        Imgproc.cvtColor(bgr, mSource, Imgproc.COLOR_BGR2RGB)
        mBinding.ivLena.showMat(mSource)
        doConvexHull()
    }

    private fun doConvexHull() {
        val binary = Mat()
        Imgproc.threshold(mGray, binary, 25.0, 255.0, Imgproc.THRESH_BINARY)
        
        val tmp = mSource.clone()
        val contours = mutableListOf<MatOfPoint>()
        val hierarchy = Mat()
        Imgproc.findContours(
            binary,
            contours,
            hierarchy,
            Imgproc.RETR_TREE,
            Imgproc.CHAIN_APPROX_SIMPLE
        )

        for (contour in contours) {
            val hull = MatOfInt()
            val defects = MatOfInt4()
            Imgproc.convexHull(contour, hull)
            val indexList = hull.toList()
            val contourList = contour.toList()
            for (i in 0 until indexList.size) {
                val index = indexList[i % indexList.size]
                val nextIndex = indexList[(i + 1) % indexList.size]
                val point = contourList[index]
                Imgproc.circle(
                    tmp,
                    point,
                    10,
                    Scalar(255.0, 255.0, 0.0),
                    2,
                    Imgproc.LINE_8,
                    0
                )
                Log.d(App.TAG, contourList[i].toString())
                Imgproc.line(
                    tmp,
                    point,
                    contourList[nextIndex],
                    Scalar(255.0, 255.0, 0.0),
                    10,
                    Imgproc.LINE_8,
                    0
                )
            }

            Imgproc.convexityDefects(contour, hull, defects)
            val defectsList = defects.toList()
            for (i in 0 until defectsList.size step 4) {
                val start = contourList[defectsList[i]]
                val end = contourList[defectsList[i + 1]]
                val far = contourList[defectsList[i + 2]]
                Imgproc.line(
                    tmp,
                    start,
                    far,
                    Scalar(0.0, 0.0, 205.0),
                    8,
                    Imgproc.LINE_8,
                    0
                )
                Imgproc.line(
                    tmp,
                    far,
                    end,
                    Scalar(0.0, 0.0, 205.0),
                    8,
                    Imgproc.LINE_8,
                    0
                )

                Imgproc.line(
                    tmp,
                    end,
                    start,
                    Scalar(0.0, 0.0, 205.0),
                    2,
                    Imgproc.LINE_8,
                    0
                )
            }
            mBinding.ivResult.showMat(tmp)
        }

        binary.release()
        hierarchy.release()
        tmp.release()
    }

    override fun onDestroy() {
        mSource.release()
        mGray.release()
        super.onDestroy()
    }
}

效果

下图中,黄色部分为凸包,蓝色部分为凸包缺陷。

凸包与凸包缺陷

源码

https://github.com/onlyloveyd/LearningAndroidOpenCV

onlyloveyd CSDN认证博客专家 Android Kotlin OpenCV
个人公众号【OpenCV or Android】,热爱Android、Kotlin、Flutter和OpenCV。毕业于华中科技大学计算机专业,曾就职于华为武汉研究所。目前在三线小城市生活,专注技术与研发。
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页