OpenCV-图像处理(12、形态学操作应用-提取水平与垂直线)

原理方法

图像形态学操作时候,可以通过自定义的结构元素实现结构元素
对输入图像一些对象敏感、另外一些对象不敏感,这样就会让敏
感的对象改变而不敏感的对象保留输出。通过使用两个最基本的
形态学操作 – 膨胀与腐蚀,使用不同的结构元素实现对输入图像
的操作、得到想要的结果。

  • 膨胀,输出的像素值是结构元素覆盖下输入图像的最大像素值
  • 腐蚀,输出的像素值是结构元素覆盖下输入图像的最小像素值

1) 二值图像与灰度图像上的膨胀操作

在这里插入图片描述

2) 二值图像与灰度图像上的腐蚀操作

在这里插入图片描述

结构元素

上述膨胀与腐蚀过程可以使用任意的结构元素
常见的形状:矩形、园、直线、磁盘形状、砖石形状等各种自定义形状。
在这里插入图片描述

提取步骤

  1. 输入图像彩色图像 imread
  2. 转换为灰度图像 – cvtColor
  3. 转换为二值图像 – adaptiveThreshold
    adaptiveThreshold(
    Mat src, // 输入的灰度图像
    Mat dest, // 二值图像
    double maxValue, // 二值图像最大值
    int adaptiveMethod // 自适应方法,只能其中之一 –
    // ADAPTIVE_THRESH_MEAN_C , ADAPTIVE_THRESH_GAUSSIAN_C
    int thresholdType,// 阈值类型
    int blockSize, // 块大小
    double C // 常量C 可以是正数,0,负数
    )

    在这里插入图片描述
    在这里插入图片描述
  4. 定义结构元素

    一个像素宽的水平线 - 水平长度 width/30
    在这里插入图片描述
    一个像素宽的垂直线 – 垂直长度 height/30
    在这里插入图片描述

  5. 开操作 (腐蚀+膨胀)提取 水平与垂直线

    bitwise_not(Mat bin, Mat dst)像素取反操作,255 – SrcPixel
    模糊(blur)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码示例

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;

int main(int argc,char** argv){
	//1、加载源图像,并检查它是否加载成功,然后显示它:
	Mat src = imread("E:/Experiment/OpenCV/Pictures/paint1.jpg");
	if(src.empty()){
		printf("Could not load Image ...");
		return -1;
	}
	namedWindow("1.input",CV_WINDOW_AUTOSIZE);
	imshow("1.input",src);
	//2、如果图像不是灰度图像转换为灰度图像:
	Mat gray_src;
	if (src.channels() == 3) 
		cvtColor(src,gray_src,CV_BGR2GRAY);
	else  
		gray_src = src;
	imshow("2.Gray Image",gray_src);
	//3、然后将灰度图像转换为二值化。注意~符号表明我们使用逆操作后版本(即bitwise_not):
	Mat binary_src;
	/*
        adaptiveThreshold( // 局部自适应阈值
            Mat src, // 输入的灰度图像
            Mat dest, // 二值图像
            double maxValue, // 二值图像最大值
            int adaptiveMethod // 自适应方法,只能其中之一 – 
                                // ADAPTIVE_THRESH_MEAN_C , ADAPTIVE_THRESH_GAUSSIAN_C 
            int thresholdType,// 阈值类型 THRESH_BINARY THRESH_BINARY_INV  阈值 T = sum(blockSize X blockSize的像素平均值) - 常量C
            int blockSize, // 块大小,只能为奇数,取图像宽或高的 1/4 到 1/6 之间? 要确保足够大?
            double C // 常量C 可以是正数,0,负数   ,让结果变得更亮一点 更大一点?
        )
    */
	adaptiveThreshold(~gray_src, binary_src, 255, CV_ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
	imshow("3.binary Image", binary_src);

	//4、以提取水平和垂直线,作为从图像中分离的结果,但首先让我们初始化的输出图像:
	Mat horizontal = binary_src.clone();
	Mat vertical = binary_src.clone();

	//5、为了提取我们所希望的对象,我们需要创建相应的结构元素。由于这里我们要提取水平线,一个相应的结构元素有以下形状:
	int horizontalsize = horizontal.cols / 30;
	Mat horizontalStructure = getStructuringElement(MORPH_RECT, Size(horizontalsize,1));
	erode(horizontal, horizontal, horizontalStructure, Point(-1, -1));
	dilate(horizontal, horizontal, horizontalStructure, Point(-1, -1));
	imshow("4.1. horizontal", horizontal);

	//6、 垂直线条的的用法也是这样,相应的结构元素如下:
	int verticalsize = vertical.rows / 30;
	Mat verticalStructure = getStructuringElement(MORPH_RECT, Size( 1,verticalsize));
	erode(vertical, vertical, verticalStructure, Point(-1, -1));
	dilate(vertical, vertical, verticalStructure, Point(-1, -1));
	imshow("4.2. vertical", vertical);

	//7、图像的边缘是有点粗糙的。由于这个原因,我们需要光顺处理边缘,以获得更平滑的结果
	 // Inverse vertical image
	bitwise_not(vertical, vertical);
	imshow("5. vertical_bit", vertical);
	// Extract edges and smooth image according to the logic
	// 1. extract edges
	// 2. dilate(edges)
	// 3. src.copyTo(smooth)
	// 4. blur smooth img
	// 5. smooth.copyTo(src, edges)
	// Step 1
	Mat edges;
	adaptiveThreshold(vertical, edges, 255, CV_ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, -2);
	imshow("6.1. edges", edges);
	// Step 2
	Mat kernel = Mat::ones(2, 2, CV_8UC1);
	dilate(edges, edges, kernel);
	imshow("6.2. dilate", edges);
	// Step 3
	Mat smooth;
	vertical.copyTo(smooth);
	// Step 4
	blur(smooth, smooth, Size(2, 2));
	// Step 5
	smooth.copyTo(vertical, edges);
	// Show final result
	imshow("6.3. smooth", vertical);

	waitKey(0);
	return 0;
}

运行结果

在这里插入图片描述
在这里插入图片描述

参考博客:

  1. https://blog.csdn.net/real_myth/article/details/53088649
  2. https://blog.csdn.net/huanghuangjin/article/details/80957750
  3. https://blog.csdn.net/LYKymy/article/details/83153621
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值