图像显示、erode腐蚀、blur模糊、Canny边缘检测
前言
本文基于OpenCV介绍一些简单的图像处理,帮助新人快速上手OpenCV。由于Chen学知有限,错误的地方欢迎大家纠正。同时有什么疑惑也可在下方留言,看到会在第一时间作出回复。
本文涉及:图像显示、腐蚀、模糊、Canny边缘检测等一些简单的图像处理。
一、图像显示
图像显示的实现过程较为简单,只需要通过imread函数载入图片的储存数据结构Mat类中,再调用imshow函数显示即可。 在显示图像的过程中,我们可能会遇到因载入原始图片尺寸太大,占据整个屏幕,而造成图像显示不全等的问题。我们可以通过创建namedWindow(),将第二个参数修改成0,来手动调节窗口大小。//图像显示
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("test.png");
if (!src.data)
{
printf("未载入图片!请指定正确的文件路径。");
return -1;
}
namedWindow("【原图】", 0);
imshow("【原图】", src);
waitKey(0);
return 0;
}
二、图像腐蚀
腐蚀作为OpenCV最基本的形态学运算之一,即用图像中暗色部分“腐蚀”掉图像中的高亮部分,主要基于getStructuringElement和erode两个函数来实现的。getStructuringElement函数返回指定的形状和尺寸的结构元素(内核矩阵)。
Mat getStructuringElement(int shape, Size esize, Point anchor = Point(-1, -1));
其中shape为内核的形状,有三种形状可供选择,分别为矩形:MORPH_RECT、交叉形:MORPH_CROSS、椭圆形:MORPH_ELLIPSE。esize为内核的尺寸。
anchor为锚点的位置,对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心点。
而erode()函数可以对输入图像用特定结构元素进行腐蚀操作,该结构元素确定腐蚀操作过程中的邻域的形状,各点像素值将被替换为对应邻域上的最小值。
void erode( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
其中src为原始图像,通道数不限,depth必须为CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。dst为输出图像,size与type与原始图像相同。
kernel用于腐蚀操作的结构元素,如果取值为Mat(),则默认使用一个3 x 3 的矩形结构元素,也可以使用getStructuringElement来创建结构元素。
anchor是结构元素的锚点位置,默认值为value(-1,-1)表示锚点位于结构元素中心。iterations表腐蚀操作被递归执行的次数,borderType为推断边缘类型,Scalar& borderValue是边缘值,后面这4个参数都有对应的默认值,没有特殊需求时都可省略不写,使用默认值。
//腐蚀操作
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("test.png");
if (!src.data)
{
printf("未载入图片!请指定正确的文件路径。");
return -1;
}
//namedWindow("【腐蚀操作 原图】", 0);
imshow("【腐蚀操作 原图】", src);
Mat element = getStructuringElement(MORPH_RECT,Size(5,5));
Mat dst;
erode(src, dst, element);
//namedWindow("【腐蚀操作 效果图】", 0);
imshow("【腐蚀操作 效果图】", dst);
waitKey(0);
return 0;
}
三、图像模糊
对图像进行均值滤波操作则可简单地实现对一幅图像的模糊操作。其中主要是基于均值滤波的blur函数。void blur( InputArray src, OutputArray dst,
Size ksize, Point anchor = Point(-1,-1),
int borderType = BORDER_DEFAULT );
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。该函数对通道是独立处理的,且可以处理任意通道数的图片,但需要注意,待处理的图片深度应该为CV_8U, CV_16U, CV_16S, CV_32F 以及 CV_64F之一。第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。可以用Clone或creat,以源图片为模板,来初始化得到所需目标图。
第三个参数,Size类型的ksize,内核的大小。一般这样写Size( w,h )来表示内核的大小( 其中,w 为像素宽度, h为像素高度)。Size(3,3)就表示3x3的核大小,Size(5,5)就表示5x5的核大小。
第四个参数,Point类型的anchor,表示锚点(即被平滑的那个点),默认值Point(-1,-1)。如果这个点坐标是负值的话,则表示取核的中心为锚点,所以默认值Point(-1,-1)则表示这个锚点在核的中心。
第五个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。默认值为BORDER_DEFAULT,我们一般不去管它。
//图像模糊
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("Kirky.jpg");
if (!src.data)
{
printf("未载入图片!请指定正确的文件路径。");
return -1;
}
//namedWindow("【模糊操作 原图】", 0);
imshow("【模糊操作 原图】", src);
Mat dst;
blur(src, dst, Size(5, 5));
imshow("【模糊操作 效果图】", dst);
waitKey(0);
return 0;
}
四、边缘检测
Canny边缘检测算子是一种多级检测算法,由John F. Canny于1986年提出,一直是作为一种标准的边缘检测算法,此后也出现了各种基于Canny算法的改进算法。时至今日,Canny算法及其各种变种仍是非常优秀的边缘检测算法。实现的步骤也较为简单,首先载入图像,将图像转为灰度图,再调用blur函数对图像进行降噪, 然后用Canny函数进行边缘检测,最后显示即可。
这里我们老惯例对Canny函数的使用方法简单地介绍一下。
void Canny( InputArray image, OutputArray edges,
double threshold1, double threshold2,
int apertureSize = 3, bool L2gradient = false );
与先前一样,image为源图像,edges为目标图像,这里输出的是边缘图像。threshold1、threshold2分别为两个阈值,阈值较小的那个值作为边缘连接,较大值用于控制边缘的初始段。这里推荐高低阈值的比为2:1或3:1。
apertureSize表示应用Sobel算子孔径的大小,其中默认值为3。
L2gradient是一个计算图像梯度幅值的标识,默认值为false。
//canny边缘检测
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat src = imread("Kirky.jpg");
if (!src.data)
{
printf("未正确载入图片!请指定正确的文件路径。");
return -1;
}
imshow("【canny边缘检测 原图】", src);
Mat image, grayImage, edges;
image.create(src.size(), src.type());
//1、将原图转成灰度图
cvtColor(src, grayImage, COLOR_BGR2GRAY);
//2、使用(3*3)内核降噪
blur(grayImage, image, Size(3, 3));
//3、运行Canny算子
Canny(image, edges, 3, 9, 3);
imshow("【canny边缘检测 效果图】", edges);
waitKey(0);
return 0;
}