前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android OpenCV(三十九):模板匹配

Android OpenCV(三十九):模板匹配

作者头像
Vaccae
发布2021-07-07 19:11:45
1.7K0
发布2021-07-07 19:11:45
举报
文章被收录于专栏:微卡智享微卡智享

什么是模板匹配?

模板匹配是一种用于在较大图像中搜索和查找模板图像位置的方法。OpenCV提供matchTemplate()方法来实现模板匹配功能。模板匹配结果返回的是灰度图像,其中每个像素表示该像素的邻域与模板匹配程度。假设输入图像的大小(W * H),模板图像的大小为(w * h),则输出图像的大小将为(W - w + 1,H - h + 1)。获得结果后,可以使用minMaxLoc()方法查找最大/最小值位置,并将其作为矩形的左上角,以(w,h)作为矩形的宽度和高度来确定模板匹配到的区域。

模板匹配原理

在要检测的图像上,从左到右,从上到下遍历这一幅图像,从上到下计算模板与重叠子图像的像素匹配度,如果匹配的程度越大,这说明相同的可能性越大。只是这个匹配度的计算有讲究。

模板匹配原理

API

代码语言:javascript
复制
public static void matchTemplate(Mat image, Mat templ, Mat result, int method, Mat mask) 

参数一:image,待匹配图像。必须是8位或者32位浮点图像。

参数二:templ,模板图像,类型与输入图像一致,并且大小不能大于源图像。

参数三:result,输出结果,必须是单通道32位浮点数,假设源图像W*H,模板图像w*h, 则结果必须为(W-w+1)*(H-h+1)的大小。

参数四:method,匹配方式标志位。若为TM_SQDIFF或者TM_SQDIFF_NORMED,计算值越小,匹配度越高,剩下的几个标志位,计算值越大,匹配度越高。

代码语言:javascript
复制
// C++: enum TemplateMatchModes
public static final int
        TM_SQDIFF = 0,
        TM_SQDIFF_NORMED = 1,
        TM_CCORR = 2,
        TM_CCORR_NORMED = 3,
        TM_CCOEFF = 4,
        TM_CCOEFF_NORMED = 5;

参数五:mask,可选掩码。必须和templ参数大小相同,要么和templ通道数相同,要么单通道。如果数据类型为#CV_8U,则将掩码解释为二进制掩码,表示仅使用掩码为非零的元素,并且权重与实际掩码值无关(一直等于1)。若数据类型为#CV_32F,掩码值将作为权重参与计算。

标记位

R(x,y)为结果矩阵, T(x^,,y^, )为模板矩阵, I(x,y)为源图像矩阵

TM_SQDIFF

R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2

with mask:

R(x,y)= \sum _{x',y'} \left( (T(x',y')-I(x+x',y+y')) \cdot M(x',y') \right)^2

TM_SQDIFF_NORMED

R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{ x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}

with mask:

R(x,y)= \frac{\sum _{x',y'} \left( (T(x',y')-I(x+x',y+y')) \cdot M(x',y') \right)^2}{\sqrt{\sum_{x',y'} \left( T(x',y') \cdot M(x',y') \right)^2 \cdot \sum_{x',y'} \left( I(x+x',y+y') \cdot M(x',y') \right)^2}}

TM_CCORR

R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y'))

with mask:

R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y') \cdot M(x',y') ^2)

TM_CCORR_NORMED

R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y'))}{\sqrt{ \sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}

with mask:

R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y') \cdot M(x',y')^2)}{\sqrt{\sum_{x',y'} \left( T(x',y') \cdot M(x',y') \right)^2 \cdot \sum_{x',y'} \left( I(x+x',y+y') \cdot M(x',y') \right)^2}}

TM_CCOEFF

R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I'(x+x',y+y'))

where

\begin{array}{l} T'(x',y')=T(x',y') - 1/(w \cdot h) \cdot \sum _{ x'',y''} T(x'',y'') \\ I'(x+x',y+y')=I(x+x',y+y') - 1/(w \cdot h) \cdot \sum _{x'',y''} I(x+x'',y+y'') \end{array}

with mask:

\begin{array}{l} T'(x',y')=M(x',y') \cdot \left( T(x',y') - \frac{1}{\sum _{x'',y''} M(x'',y'')} \cdot \sum _{x'',y''} (T(x'',y'') \cdot M(x'',y'')) \right) \\ I'(x+x',y+y')=M(x',y') \cdot \left( I(x+x',y+y') - \frac{1}{\sum _{x'',y''} M(x'',y'')} \cdot \sum _{x'',y''} (I(x+x'',y+y'') \cdot M(x'',y'')) \right) \end{array}

TM_CCOEFF_NORMED

R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} }

操作

代码语言:javascript
复制
/**
 * 模板匹配
 * author: yidong
 * 2020/10/23
 */
class MatchTemplateActivity : AppCompatActivity() {

    private lateinit var mBinding: ActivityMatchTemplateBinding
    private lateinit var mRgb: Mat
    private lateinit var mTemplate: Mat
    private var method = Imgproc.TM_SQDIFF
        set(value) {
            field = value
            doMatch(field)
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_match_template)
        title = "TM_SQDIFF"
        val bgr = Utils.loadResource(this, R.drawable.kobe)
        mRgb = Mat()
        mTemplate = Mat()
        Imgproc.cvtColor(bgr, mRgb, Imgproc.COLOR_BGR2RGB)
        val templateBgr = Utils.loadResource(this, R.drawable.kobe_template)
        Imgproc.cvtColor(templateBgr, mTemplate, Imgproc.COLOR_BGR2RGB)
        mBinding.ivLena.showMat(mTemplate)
        doMatch(Imgproc.TM_CCOEFF)
    }

    private fun doMatch(method: Int) {
        val tmp = mRgb.clone()
        val result = Mat()
        Imgproc.matchTemplate(mRgb, mTemplate, result, method)
        val minMaxLoc = Core.minMaxLoc(result)
        val topLeft = if (method == Imgproc.TM_SQDIFF || method == Imgproc.TM_SQDIFF_NORMED) {
            minMaxLoc.minLoc;
        } else {
            minMaxLoc.maxLoc;
        }
        val rect = Rect(topLeft, Size(mTemplate.cols().toDouble(), mTemplate.rows().toDouble()))
        Imgproc.rectangle(tmp, rect, Scalar(255.0, 0.0, 0.0), 4, Imgproc.LINE_8)
        mBinding.ivResult.showMat(mRgb)
        tmp.release()
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu_match_template, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.match_tm_sqdiff -> {
                method = Imgproc.TM_SQDIFF
                title = "TM_SQDIFF"
            }
            R.id.match_tm_sqdiff_normed -> {
                method = Imgproc.TM_SQDIFF_NORMED
                title = "TM_SQDIFF_NORMED"
            }
            R.id.match_tm_ccoeff -> {
                method = Imgproc.TM_CCOEFF
                title = "TM_CCOEFF"
            }

            R.id.match_tm_ccoeff_normed -> {
                method = Imgproc.TM_CCOEFF_NORMED
                title = "TM_CCOEFF_NORMED"
            }
            R.id.match_tm_ccorr -> {
                method = Imgproc.TM_CCORR
                title = "TM_CCORR"
            }
            R.id.match_tm_ccorr_normed -> {
                method = Imgproc.TM_CCORR_NORMED
                title = "TM_CCORR_NORMED"
            }
        }
        return true
    }

    override fun onDestroy() {
        mTemplate.release()
        mRgb.release()
        super.onDestroy()
    }
}

结果

模板匹配结果

源码

https://github.com/onlyloveyd/LearningAndroidOpenCV

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微卡智享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是模板匹配?
  • 模板匹配原理
  • API
  • 标记位
    • TM_SQDIFF
      • TM_SQDIFF_NORMED
        • TM_CCORR
          • TM_CCORR_NORMED
            • TM_CCOEFF
              • TM_CCOEFF_NORMED
              • 操作
              • 结果
              • 源码
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档