上一个教程 :更多形态变换
下一个教程 : 使用形态学操作提取水平线和垂直线
原作者 | 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) A⊛B=(A⊖B1)∩(AC⊖B2)
因此,"命中或遗漏 "操作包括三个步骤:
- 用结构元素 B1 冲淡图像 A。
- 用结构元素 B2 冲淡图像 A 的补码(Ac)。
- 与步骤 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() 函数就可以了。
其他示例
在这里,您可以找到对之前使用过的相同输入图像应用不同内核后的输出结果: