图像处理:基础——Hit-or-Miss OpenCV v4.8.0

上一个教程更多形态变换

下一个教程使用形态学操作提取水平线和垂直线

原作者Lorena García
兼容性OpenCV >= 3.0

目标

在本教程中,你将学习如何使用 “命中或遗漏变换”(又称 “命中和遗漏变换”)在二值图像中找到给定的配置或模式。这种变换也是更高级形态学操作(如稀疏化或剪枝)的基础。

我们将使用 OpenCV 函数 morphologyEx()

Hit-or-Miss理论

形态运算符根据图像的形状对图像进行处理。这些算子将一个或多个结构元素应用于输入图像,从而获得输出图像。两种基本形态学操作是侵蚀和扩张。这两种操作的组合可产生高级形态变换,如开放、闭合或顶帽变换。要进一步了解这些操作和其他基本形态学操作,请参阅之前的教程(腐蚀和膨胀)和(更多形态学变换)。

命中或遗漏变换可用于查找二值图像中的模式。特别是,它可以找到那些邻域与第一个结构元素 B1 的形状相匹配,但同时又与第二个结构元素 B2 的形状不匹配的像素。在数学上,对图像 A 的操作可以表示如下:

A ⊛ B = ( A ⊖ B 1 ) ∩ ( A C ⊖ B 2 ) A\circledast B=\left( A\ominus B_1 \right) \cap \left( A^C\ominus B_2 \right) AB=(AB1)(ACB2)

因此,"命中或遗漏 "操作包括三个步骤:

  1. 用结构元素 B1 冲淡图像 A。
  2. 用结构元素 B2 冲淡图像 A 的补码(Ac)。
  3. 与步骤 1 和步骤 2 的结果相加。

结构元素 B1 和 B2 可以合并为一个元素 B:

在这里插入图片描述

结构元素(内核)。左:"命中 "的内核。中间:"未命中 "的内核。右图:最终合并的内核

在本例中,我们正在寻找一种模式,其中中心像素属于背景,而北、南、东和西像素属于前景。邻域中的其他像素可以是任何类型的,我们并不关心它们。现在,让我们把这个内核应用到输入图像中:

在这里插入图片描述

输入二值图像

在这里插入图片描述

输出二进制图像

您可以看到,该模式只在图像中的一个位置出现。

代码

C++
与上一示例相对应的代码如下所示。

您也可以从此处下载

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
int main(){
 Mat input_image = (Mat_<uchar>(8, 8) <<
 0, 0, 0, 0, 0, 0, 0, 0,
 0, 255, 255, 255, 0, 0, 0, 255,
 0, 255, 255, 255, 0, 0, 0, 0,
 0, 255, 255, 255, 0, 255, 0, 0,
 0, 0, 255, 0, 0, 0, 0, 0,
 0, 0, 255, 0, 0, 255, 255, 0,
 0, 255, 0, 255, 0, 0, 255, 0,
 0, 255, 255, 255, 0, 0, 0, 0);
 Mat kernel = (Mat_<int>(3, 3) <<
 0, 1, 0,
 1, -1, 1,
 0, 1, 0);
 Mat output_image;
 morphologyEx(input_image, output_image, MORPH_HITMISS, kernel);
 const int rate = 50;
 kernel = (kernel + 1) * 127;
 kernel.convertTo(kernel, CV_8U);
 resize(kernel, kernel, Size(), rate, rate, INTER_NEAREST);
 imshow("kernel", kernel);
 moveWindow("kernel", 0, 0);
 resize(input_image, input_image, Size(), rate, rate, INTER_NEAREST);
 imshow("Original", input_image);
 moveWindow("Original", 0, 200);
 resize(output_image, output_image, Size(), rate, rate, INTER_NEAREST);
 imshow("Hit or Miss", output_image);
 moveWindow("Hit or Miss", 500, 200);
 waitKey(0);
 return 0;
 }

Java
与上一示例相对应的代码如下所示。

您也可以从此处下载

import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgproc.Imgproc;
class HitMissRun{
 public void run() {
 Mat input_image = new Mat( 8, 8, CvType.CV_8UC1 );
 int row = 0, col = 0;
 input_image.put(row ,col,
 0, 0, 0, 0, 0, 0, 0, 0,
 0, 255, 255, 255, 0, 0, 0, 255,
 0, 255, 255, 255, 0, 0, 0, 0,
 0, 255, 255, 255, 0, 255, 0, 0,
 0, 0, 255, 0, 0, 0, 0, 0,
 0, 0, 255, 0, 0, 255, 255, 0,
 0, 255, 0, 255, 0, 0, 255, 0,
 0, 255, 255, 255, 0, 0, 0, 0);
 Mat kernel = new Mat( 3, 3, CvType.CV_16S );
 kernel.put(row ,col,
 0, 1, 0,
 1, -1, 1,
 0, 1, 0 );
 Mat output_image = new Mat();
 Imgproc.morphologyEx(input_image, output_image, Imgproc.MORPH_HITMISS, kernel);
 int rate = 50;
 Core.add(kernel, new Scalar(1), kernel);
 Core.multiply(kernel, new Scalar(127), kernel);
 kernel.convertTo(kernel, CvType.CV_8U);
 Imgproc.resize(kernel, kernel, new Size(), rate, rate, Imgproc.INTER_NEAREST);
 HighGui.imshow("kernel", kernel);
 HighGui.moveWindow("kernel", 0, 0);
 Imgproc.resize(input_image, input_image, new Size(), rate, rate, Imgproc.INTER_NEAREST);
 HighGui.imshow("Original", input_image);
 HighGui.moveWindow("Original", 0, 200);
 Imgproc.resize(output_image, output_image, new Size(), rate, rate, Imgproc.INTER_NEAREST);
 HighGui.imshow("Hit or Miss", output_image);
 HighGui.moveWindow("Hit or Miss", 500, 200);
 HighGui.waitKey(0);
 System.exit(0);
 }
}
public class HitMiss
{
 public static void main(String[] args) {
 // 加载本地OpenCV库
 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
 new HitMissRun().run();
 }
}

Python
与上一示例相对应的代码如下所示。

您也可以从此处下载

import cv2 as cv
import numpy as np
input_image = np.array((
 [0, 0, 0, 0, 0, 0, 0, 0],
 [0, 255, 255, 255, 0, 0, 0, 255],
 [0, 255, 255, 255, 0, 0, 0, 0],
 [0, 255, 255, 255, 0, 255, 0, 0],
 [0, 0, 255, 0, 0, 0, 0, 0],
 [0, 0, 255, 0, 0, 255, 255, 0],
 [0,255, 0, 255, 0, 0, 255, 0],
 [0, 255, 255, 255, 0, 0, 0, 0]), dtype="uint8")
kernel = np.array((
 [0, 1, 0],
 [1, -1, 1],
 [0, 1, 0]), dtype="int")
output_image = cv.morphologyEx(input_image, cv.MORPH_HITMISS, kernel)
rate = 50
kernel = (kernel + 1) * 127
kernel = np.uint8(kernel)
kernel = cv.resize(kernel, None, fx = rate, fy = rate, interpolation = cv.INTER_NEAREST)
cv.imshow("kernel", kernel)
cv.moveWindow("kernel", 0, 0)
input_image = cv.resize(input_image, None, fx = rate, fy = rate, interpolation = cv.INTER_NEAREST)
cv.imshow("Original", input_image)
cv.moveWindow("Original", 0, 200)
output_image = cv.resize(output_image, None , fx = rate, fy = rate, interpolation = cv.INTER_NEAREST)
cv.imshow("Hit or Miss", output_image)
cv.moveWindow("Hit or Miss", 500, 200)
cv.waitKey(0)
cv.destroyAllWindows()

正如您所看到的,使用带有操作类型 MORPH_HITMISS 和所选内核的 morphologyEx() 函数就可以了。

其他示例

在这里,您可以找到对之前使用过的相同输入图像应用不同内核后的输出结果:

在这里插入图片描述

查找右上角的内核和输出结果

在这里插入图片描述

查找左端点的内核和输出结果
现在试试你自己的模式!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值