形态学:提取横线、竖线

原理

  1. 提取横线:
    在这里插入图片描述
    经过先腐蚀,再膨胀,得到直线。



  1. 提取竖线:
    在这里插入图片描述
    经过先腐蚀,再膨胀,得到竖线。



代码

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

void show_wait_destroy(const char* winname, cv::Mat image)
{
	static uchar i=0;
	imshow(winname,image);
	cv::moveWindow(winname,0,(++i)*(200));
}

int main(void)
{
	
	Mat src = imread("../res/src.png");
	if(src.empty())
	{
		cout << "load the image failed" << endl;
	}


	Mat gray;
	if(src.channels() == 3)
	{
		cv::cvtColor(src,gray,cv::COLOR_BGR2GRAY);
	}
	else
	{
		gray = src;
	}

//转化成二值图像
	Mat bw;
	cv::adaptiveThreshold(~gray,bw,255,cv::ADAPTIVE_THRESH_MEAN_C,cv::THRESH_BINARY,15,-2);
	show_wait_destroy("binary",bw);
	
	
	Mat horizontal = bw.clone();
	Mat vertical = bw.clone();

//提取横线
	int horizontal_size=horizontal.cols/30;
	Mat horizontalStructure = cv::getStructuringElement(cv::MORPH_RECT,Size(horizontal_size,1));

	cv::erode(horizontal,horizontal,horizontalStructure);
	cv::dilate(horizontal,horizontal,horizontalStructure);

	show_wait_destroy("horizontal",horizontal);



//提取竖线
	int vertical_size = vertical.rows/30;
	Mat verticalStructure = getStructuringElement(MORPH_RECT,Size(1,vertical_size));

	erode(vertical,vertical,verticalStructure);
	dilate(vertical,vertical,verticalStructure);

	bitwise_not(vertical,vertical);
	show_wait_destroy("vertical",vertical);

//提取边界
	Mat edges;
	cv::adaptiveThreshold(vertical,edges,255,cv::ADAPTIVE_THRESH_MEAN_C,cv::THRESH_BINARY,3,-2);
	show_wait_destroy("vertical_1",edges);
//膨胀边界
	Mat kernel = Mat::ones(2,2,CV_8UC1);
	dilate(edges,edges,kernel);
	show_wait_destroy("vertical_2",edges);
	
//平滑vertical
	Mat smooth;
	vertical.copyTo(smooth);
	blur(smooth,smooth,Size(2,2));

//将平滑之后的边界,覆盖到vertical,实现对vertical平滑边界的效果
	smooth.copyTo(vertical,edges);
	show_wait_destroy("final",vertical);

	waitKey(0);

	return 0;
};


原图
在这里插入图片描述
结果:
horizontal:
在这里插入图片描述

vertical:
在这里插入图片描述



源码分析:

	Mat src = imread("../res/src.png");
	if(src.empty())
	{
		cout << "load the image failed" << endl;
	}


	Mat gray;
	if(src.channels() == 3)
	{
		cv::cvtColor(src,gray,cv::COLOR_BGR2GRAY);
	}
	else
	{
		gray = src;
	}
	imshow("src",src);

读取原图,再转化成灰度图像
在这里插入图片描述





Mat bw;
cv::adaptiveThreshold(~gray,bw,255,cv::ADAPTIVE_THRESH_MEAN_C,cv::THRESH_BINARY,15,-2);
show_wait_destroy("binary",bw);

将灰度图像转成二值图像,使用的是adaptiveThreshold函数,各个参数的综合意义:如果原图锚点的的值大于领域(核的边长15)的平均值,则取255,否则取0。
在这里插入图片描述





    Mat horizontal = bw.clone();
	Mat vertical = bw.clone();

	int horizontal_size=horizontal.cols/30;
	Mat horizontalStructure = cv::getStructuringElement(cv::MORPH_RECT,Size(horizontal_size,1));

	cv::erode(horizontal,horizontal,horizontalStructure);
	cv::dilate(horizontal,horizontal,horizontalStructure);

	show_wait_destroy("horizontal",horizontal);

创建一个核大小:(1, cols/30), 用其进行对原图先腐蚀再膨胀,得到结果:
在这里插入图片描述





	int vertical_size = vertical.rows/30;
	Mat verticalStructure = getStructuringElement(MORPH_RECT,Size(1,vertical_size));

	erode(vertical,vertical,verticalStructure);
	dilate(vertical,vertical,verticalStructure);

	bitwise_not(vertical,vertical);
	show_wait_destroy("vertical",vertical);

创建一个核大小:(vertical.rows/30 , 1), 用其进行对原图先腐蚀再膨胀,然后取反得到结果:
在这里插入图片描述







    Mat edges;
	cv::adaptiveThreshold(vertical,edges,255,cv::ADAPTIVE_THRESH_MEAN_C,cv::THRESH_BINARY,3,-2);
	show_wait_destroy("vertical_1",edges);

因为领域大小选择了3,当锚点在白色区域的时候,src=领域均值的,所以赋值为0,所以只有在黑白交接处 src>均值,赋值为1,最后得到的结果就是提取边界。
在这里插入图片描述





	Mat kernel = Mat::ones(2,2,CV_8UC1);
	dilate(edges,edges,kernel);
	show_wait_destroy("vertical_2",edges);

对边界进行膨胀
在这里插入图片描述





	Mat smooth;
	vertical.copyTo(smooth);
	blur(smooth,smooth,Size(2,2));

	smooth.copyTo(vertical,edges);
	show_wait_destroy("final",vertical);

先将原始的vertical 进行均值平滑,再将结果以edges为mask,复制到vertical。(等价于只将平滑后的边界覆盖到vertical,实现平滑边界的效果)

在这里插入图片描述


官方API

(1)

  • void cv::adaptiveThreshold(
    InputArray src,      // 输入图像
    OutputArray dst,      //输出图像
    double maxValue,      //对于二值图像转化的目标值
    int adaptiveMethod,      //自适应阈值算法
    int thresholdType,      //阈值的类型
    int blockSize,      //用来计算像素阈值的领域的大小(3,5,7等)
    double C       //偏移常数C,最终得到的阈值-C。
    )

参数 adaptiveMethod:自适应阈值算法

算法
ADAPTIVE_THRESH_MEAN_C
ADAPTIVE_THRESH_GAUSSIAN_C

参数 thresholdType:阈值类型

常用类型
THRESH_BINARY
THRESH_BINARY_INV



(2)

  • void cv::Mat::copyTo (
    OutputArray m,      //目的图像
    InputArray mask       //和this大小一样的掩膜,掩膜不为0的区域将this相应的区域复制到目的图像中,为0区域:目的图像还是原来的值
    ) const

猜你喜欢

转载自blog.csdn.net/zzyczzyc/article/details/85014144
今日推荐