7种图像处理形态学(2)
视频讲解如下:
当前系列所有demo下载地址:
https://github.com/GaoRenBao/OpenCv4-Demo
不同编程语言对应的OpenCv版本以及开发环境信息如下:
语言 | OpenCv版本 | IDE |
C# | OpenCvSharp4.4.8.0.20230708 | Visual Studio 2022 |
C++ | OpenCv-4.5.5-vc14_vc15 | Visual Studio 2022 |
Python | OpenCv-Python (4.6.0.66) | PyCharm Community Edition 2022.1.3 |
在上一章节中,给大家演示了,如何使用erode进行腐蚀操作,以及使用dilate进行膨胀操作,这一章节,给大家演示,如何使用morphologyEx进行七种图像处理形态学操作。
morphologyEx除了常用的七种形态学操作外,其实还有一种比较特殊的操作,叫“HitMiss”,俗称“击中击不中”,所以morphologyEx一共有8种形态学操作,这8种操作如下:
C# | C++ | Python | 说明 |
MorphTypes.Erode | MORPH_ERODE | cv2.MORPH_ERODE | 0:腐蚀 |
MorphTypes.Dilate | MORPH_DILATE | cv2.MORPH_DILATE | 1:膨胀 |
MorphTypes.Open | MORPH_OPEN | cv2.MORPH_OPEN | 2:开运算 |
MorphTypes.Close | MORPH_CLOSE | cv2.MORPH_CLOSE | 3:闭运算 |
MorphTypes.Gradient | MORPH_GRADIENT | cv2.MORPH_GRADIENT | 4:梯度 |
MorphTypes.TopHat | MORPH_TOPHAT | cv2.MORPH_TOPHAT | 5:顶帽 |
MorphTypes.BlackHat | MORPH_BLACKHAT | cv2.MORPH_BLACKHAT | 6:黑帽 |
MorphTypes.HitMiss | MORPH_HITMISS | cv2.MORPH_HITMISS | 7:击中击不中 |
MorphTypes 类的C#官方代码如下:
//
// 摘要:
// Type of morphological operation
[Flags]
public enum MorphTypes
{
Erode = 0,
Dilate = 1,
//
// 摘要:
// an opening operation
Open = 2,
//
// 摘要:
// a closing operation
Close = 3,
//
// 摘要:
// Morphological gradient
Gradient = 4,
//
// 摘要:
// "Top hat"
TopHat = 5,
//
// 摘要:
// "Black hat"
BlackHat = 6,
//
// 摘要:
// "hit and miss"
HitMiss = 7
}
经过站长测试发现,morphologyEx除了前七种形态学操作外,第八种HitMiss操作出现不同平台下运行结果不一样的现象,以15*15的核为基础,C#、C++、Python三个环境下HitMiss操作的对比图如下:

通过上面的对比,你会发现C#和Python的执行效果基本是一样的,唯独C++的不一样,刚开始我还怀疑是不是我的OpenCv版本的问题,后来我把C#的OpenCvSharp3-AnyCPU版本修改成了OpenCvSharp4版本,结果发现OpenCvSharp4和OpenCvSharp3-AnyCPU的效果是一样的。C++和Python的其他OpenCv版本站长没试过,但可以肯定的是这里面肯定有个版本的OpenCv是有问题的。这种现在在前面的《支持向量机之SVM引导》章节中其实也发现过,所以大家选择OpenCv和编程语言的时候,一定要慎重。
《支持向量机之SVM引导》:/Course?Id=1§ion=22
OpenCvSharp4版本需要安装OpenCvSharp4和OpenCvSharp4.runtime.win两个库,不然会报错,如下图

另外七种形态学操作的对比如下:







本章节的所有代码如下:
C#版本代码
using OpenCvSharp;
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp
{
public partial class Form1 : Form
{
public int g_element = 15; //核
Mat srcImage; // 原图
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// 载入原图
srcImage = Cv2.ImRead("../../../images/girl4.jpg");
// 显示原图
Cv2.ImShow("【原图】", srcImage);
// 异步操作
new Task(() => { MyMorphology(); }).Start();
}
private void hScrollBar1_ValueChanged(object sender, EventArgs e)
{
g_element = hScrollBar1.Value;
label1.Text = g_element.ToString();
}
private void MyMorphology()
{
// 一定要放在while外面初始化,不然会出现内存问题
Mat out1 = new Mat();
Mat out2 = new Mat();
Mat out3 = new Mat();
Mat out4 = new Mat();
Mat out5 = new Mat();
Mat out6 = new Mat();
Mat out7 = new Mat();
Mat out8 = new Mat();
Mat des = new Mat();
while (true)
{
// 定义核大小
Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(g_element, g_element));
// 进行形态学腐蚀操作
Cv2.MorphologyEx(srcImage, out1, MorphTypes.Erode, element);
// 进行形态学膨胀操作
Cv2.MorphologyEx(srcImage, out2, MorphTypes.Dilate, element);
// 进行形态学开运算操作
Cv2.MorphologyEx(srcImage, out3, MorphTypes.Open, element);
// 进行形态学闭运算操作
Cv2.MorphologyEx(srcImage, out4, MorphTypes.Close, element);
// 进行形态学梯度操作
Cv2.MorphologyEx(srcImage, out5, MorphTypes.Gradient, element);
// 进行形态学顶帽操作
Cv2.MorphologyEx(srcImage, out6, MorphTypes.TopHat, element);
// 进行形态学黑帽操作
Cv2.MorphologyEx(srcImage, out7, MorphTypes.BlackHat, element);
// 进行形态学击中击不中操作
Cv2.CvtColor(srcImage, des, ColorConversionCodes.BGR2GRAY);
Cv2.MorphologyEx(des, out8, MorphTypes.HitMiss, element);
// 显示效果图
Cv2.PutText(out1, "C#",new Point(10, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 0, 255), 2);
Cv2.PutText(out2, "C#",new Point(10, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 0, 255), 2);
Cv2.PutText(out3, "C#",new Point(10, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 0, 255), 2);
Cv2.PutText(out4, "C#",new Point(10, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 0, 255), 2);
Cv2.PutText(out5, "C#",new Point(10, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 0, 255), 2);
Cv2.PutText(out6, "C#",new Point(10, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 0, 255), 2);
Cv2.PutText(out7, "C#",new Point(10, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 0, 255), 2);
Cv2.PutText(out8, "C#",new Point(10, 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 0, 255), 2);
Cv2.ImShow("腐蚀【效果图】", out1);
Cv2.ImShow("膨胀【效果图】", out2);
Cv2.ImShow("开运算【效果图】", out3);
Cv2.ImShow("闭运算【效果图】", out4);
Cv2.ImShow("梯度【效果图】", out5);
Cv2.ImShow("顶帽【效果图】", out6);
Cv2.ImShow("黑帽【效果图】", out7);
Cv2.ImShow("击中击不中【效果图】", out8);
Cv2.WaitKey(30);
}
}
}
}
C++版本代码
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
void MyMorphology(int, void*);
int g_element = 15; // 核
Mat srcImage; // 原图
int main()
{
// 载入原图
srcImage = imread("../images/girl4.jpg");
//// 创建滑动条窗体
//namedWindow("【原图】", 1);
//createTrackbar("核", "【原图】", &g_element, 100, MyMorphology);
//MyMorphology(g_element, 0);
//waitKey(0);
/****** 形态学击中击不中 独立测试部分(网络资源) ******/
//创建输入图像和核
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);
resize(input_image, input_image, Size(), rate, rate, INTER_NEAREST);
imshow("Original", input_image);
resize(output_image, output_image, Size(), rate, rate, INTER_NEAREST);
imshow("Hit or Miss", output_image);
waitKey(0);
return 0;
}
void MyMorphology(int, void*)
{
// 创建窗口
namedWindow("腐蚀【效果图】");
namedWindow("膨胀【效果图】");
namedWindow("开运算【效果图】");
namedWindow("闭运算【效果图】");
namedWindow("梯度【效果图】");
namedWindow("顶帽【效果图】");
namedWindow("黑帽【效果图】");
namedWindow("击中击不中【效果图】");
// 显示原图
imshow("【原图】", srcImage);
//定义核
if (g_element <= 0) g_element = 1;
Mat element = getStructuringElement(MORPH_RECT, Size(g_element, g_element));
//进行形态学腐蚀操作
Mat out1;
morphologyEx(srcImage, out1, MORPH_ERODE, element);
//进行形态学膨胀操作
Mat out2;
morphologyEx(srcImage, out2, MORPH_DILATE, element);
//进行形态学开运算操作
Mat out3;
morphologyEx(srcImage, out3, MORPH_OPEN, element);
//进行形态学闭运算操作
Mat out4;
morphologyEx(srcImage, out4, MORPH_CLOSE, element);
//进行形态学梯度操作
Mat out5;
morphologyEx(srcImage, out5, MORPH_GRADIENT, element);
//进行形态学顶帽操作
Mat out6;
morphologyEx(srcImage, out6, MORPH_TOPHAT, element);
//进行形态学黑帽操作
Mat out7;
morphologyEx(srcImage, out7, MORPH_BLACKHAT, element);
// 进行形态学击中击不中操作,需要将图像转灰度
Mat des, out8;
cvtColor(srcImage, des, COLOR_BGR2GRAY);
morphologyEx(des, out8, MORPH_HITMISS, element);
// 显示效果图
// opencv3:CV_AA
// opencv4:LINE_AA
putText(out1, "C++", Point(10, 30), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(out2, "C++", Point(10, 30), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(out3, "C++", Point(10, 30), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(out4, "C++", Point(10, 30), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(out5, "C++", Point(10, 30), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(out6, "C++", Point(10, 30), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(out7, "C++", Point(10, 30), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
putText(out8, "C++", Point(10, 30), FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
imshow("腐蚀【效果图】", out1);
imshow("膨胀【效果图】", out2);
imshow("开运算【效果图】", out3);
imshow("闭运算【效果图】", out4);
imshow("梯度【效果图】", out5);
imshow("顶帽【效果图】", out6);
imshow("黑帽【效果图】", out7);
imshow("击中击不中【效果图】", out8);
waitKey(30);
}
Python版本代码
import cv2
import numpy as np
# 下面是击中击不中操作测试
def demo1():
array1 = [[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]]
array2 = [[0, 1, 0], [1, -1, 1], [0, 1, 0]]
def createAlphaMat(mat, array):
imgH = mat.shape[0]
imgW = mat.shape[1]
for w in range(imgW):
for h in range(imgH):
mat[h, w] = array[h][w]
return mat
# 创建一个2通道的图片
input_image = np.ones((8, 8), np.uint8)
input_image = createAlphaMat(input_image, array1)
kernel = np.ones((3, 3), np.uint8)
kernel = createAlphaMat(kernel, array2)
# 进行形态学击中击不中操作
output_image = cv2.morphologyEx(input_image, cv2.MORPH_HITMISS, kernel)
# 为便于观察,将输入图像、输出图像、核放大五十倍,显示
# 一个小方块表示一个像素
rate = 400
kernel = (kernel + 1) * 127;
kernel = cv2.resize(kernel, (rate, rate), interpolation=cv2.INTER_NEAREST)
cv2.imshow("kernel", kernel);
input_image = cv2.resize(input_image, (rate, rate), interpolation=cv2.INTER_NEAREST)
cv2.imshow("Original", input_image);
output_image = cv2.resize(output_image, (rate, rate), interpolation=cv2.INTER_NEAREST)
cv2.imshow("Hit or Miss", output_image);
cv2.waitKey(0)
# 下面是形态学操作
def demo2():
# 载入原图
srcImage = cv2.imread('../images/girl4.jpg')
# 显示原图
cv2.imshow('image', srcImage)
# 定义核大小
element = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 15))
# 进行形态学腐蚀操作
out1 = cv2.morphologyEx(srcImage, cv2.MORPH_ERODE, element)
# 进行形态学膨胀操作
out2 = cv2.morphologyEx(srcImage, cv2.MORPH_DILATE, element)
# 进行形态学开运算操作
out3 = cv2.morphologyEx(srcImage, cv2.MORPH_OPEN, element)
# 进行形态学闭运算操作
out4 = cv2.morphologyEx(srcImage, cv2.MORPH_CLOSE, element)
# 进行形态学梯度操作
out5 = cv2.morphologyEx(srcImage, cv2.MORPH_GRADIENT, element)
# 进行形态学顶帽操作
out6 = cv2.morphologyEx(srcImage, cv2.MORPH_TOPHAT, element)
# 进行形态学黑帽操作
out7 = cv2.morphologyEx(srcImage, cv2.MORPH_BLACKHAT, element)
# 进行形态学击中击不中操作
des = cv2.cvtColor(srcImage, cv2.COLOR_BGR2GRAY)
out8 = cv2.morphologyEx(des, cv2.MORPH_HITMISS, element)
# 显示效果图
font = cv2.FONT_HERSHEY_COMPLEX # 设置字体
out1 = cv2.putText(out1, "Python", (10, 30), font, 1, (0, 0, 255), 2)
out2 = cv2.putText(out2, "Python", (10, 30), font, 1, (0, 0, 255), 2)
out3 = cv2.putText(out3, "Python", (10, 30), font, 1, (0, 0, 255), 2)
out4 = cv2.putText(out4, "Python", (10, 30), font, 1, (0, 0, 255), 2)
out5 = cv2.putText(out5, "Python", (10, 30), font, 1, (0, 0, 255), 2)
out6 = cv2.putText(out6, "Python", (10, 30), font, 1, (0, 0, 255), 2)
out7 = cv2.putText(out7, "Python", (10, 30), font, 1, (0, 0, 255), 2)
out8 = cv2.putText(out8, "Python", (10, 30), font, 1, (0, 0, 255), 2)
cv2.imshow('MORPH_ERODE', out1)
cv2.imshow('MORPH_DILATE', out2)
cv2.imshow('MORPH_OPEN', out3)
cv2.imshow('MORPH_CLOSE', out4)
cv2.imshow('MORPH_GRADIENT', out5)
cv2.imshow('MORPH_TOPHAT', out6)
cv2.imshow('MORPH_BLACKHAT', out7)
cv2.imshow('MORPH_HITMISS', out8)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
demo1()
demo2()