OpenCV

title:OpenCV
time:2019年9月7日09:46:56


OpenCV基础1:

介绍

  • 是计算机视觉开源库,主要算法设计图像处理和机器学习相关方法。
  • 在多数图像相关的应用程序中被采用个,BSD许可,可以免费应用在商业和研究领域
  • 目前SDK支持语言:Java、Python、IOS和Android
  • 其他Matlab、Halcon

配置

  • 参考

  • 添加系统变量path:D:\Microsoft\opencv\build\x64\vc15\bin

  • 把opencv\build\x64\vc15\bin中几个应用程序扩展全都放进window/sysWOW64和system32中

  • 项目属性管理器中x64中右键

  • vc++目录中包含目录

    • D:\Microsoft\opencv\build\include\opencv2
    • D:\Microsoft\opencv\build\include
  • 库目录

    • D:\Microsoft\opencv\build\x64\vc15\lib
  • 链接器中

    • opencv_world411d.lib

番茄工具的使用

  • 参考

加载、修改、保存图像

  • 加载图像(cv::imread)

    • 加载图像文件成为一个Mat对象,

    • 第一个参数是图像文件名称

    • 表示加载的图像是什么类型,支持常见的三个参数值

      • IMREAD_UNCHANGED(<0)表示加载原图,不做任何改变
      • IMREAD_GRAYSCALE(0)表示把原图作为灰度图像加载进来
      • IMREAD_COLOR(>O)表示把原图作为RGB图像加载进来
    • 注意:支持JPG、PNG、TIFF等常见格式图像文件加载

  • 显示图像(cv::namedWindos与cv::inshow)

    • namedWindos功能是创建一个OpenCV窗口,它是由OpenCV自动创建与释放,你无需销毁
    • namedWindow(“WindowTItle”,WINDOW_AUTOSIZE)
      • WINDOW_AUTOSIZE会自动根据图像大小,显示窗口大小,不能人为改变窗口大小
      • WINDOW_NORMAL,跟QT集成的时候会使用,允许修改窗口大小。
    • imshow根据窗口名称显示图像到指定的窗口上去
      • 第一个参数是窗口名称
      • 第二个参数是Mat对象
  • 修改图像(cv::cvtColor)

    • cvtColor的功能是把图像从一个彩色空间转换到另外一个色彩空间
    • 参数1:表示原图像(MAT)
    • 参数2:表示新图像(MAT)
    • 参数3:表示目标色彩空间如:COLOR_BGR2GRAY ,CORLOR_BGR2HLS
  • 保存图像(cv::imwrite)

    • 保存图像文件到指定目录路径
      • 参数1:路径(1.png就是png的色彩空间,1.tiff表示其他,根据需要自己定)
      • 参数2:图片(MAT)
    • 只有8位、16位的PNG、JPG、Tiff文件格式而且是单通道或者三通道的BGR的图像才可以通过这种方式保存
    • 保存PNG的时候可以保存透明通道的图片
    • 可以指定压缩参数
  • waitKey(0)

    • 窗口的保留时间,如不设置,会秒退

矩阵的掩膜操作

  • ​ 像素范围处理saturate_cast

    • saturate_cast(-100),返回0
    • saturate_cast(288),返回1
    • saturate_cast(100)返回100
    • 这个函数的功能是确保RGB值的范围在0~255之间
  • 对比度增加

    • 这个公式的意思就是如果你选中 的这个中心点比周围的暗,那就让它更暗,如果比周围的亮,那就让它更亮,当你把这个操作扩展到整个图像之后,图像之间的亮暗差距会变得更大,也就是对比度会更大row=1 而不是0,因为一个图像的边缘点没有四周进行对比,不能使用公式,所以循环从1开始,去掉了最外圈像素没有办法进行比较的点

    • int cols = (src.cols-1) * src.channels();
      	int offsetx = src.channels();
      	int rows = src.rows;
      
      	dst = Mat::zeros(src.size(), src.type());
      	for (int row = 1; row < (rows - 1); row++) {
      		const uchar* previous = src.ptr(row - 1);
      		const uchar* current = src.ptr(row);
      		const uchar* next = src.ptr(row + 1);
      		uchar* output = dst.ptr(row);
      		for (int col = offsetx; col < cols; col++) {
      			output[col] = saturate_cast(5 * current[col] - (current[col- offsetx] + current[col+ offsetx] + previous[col] + next[col]));
      		}
      	}
      
  • 而OpenCV把这部分代码封装了起来

  • 函数调用filter2D功能

    • 定义掩膜:

      Mat kernal = (Mat_(3,3)<<0,-1,0,-1,5, -1, 0, -1, 0);

    • filter2D( src, dst, src.depth(), kernel );其中src与dst是Mat类型变量、src.depth表示位图深度,默认是-1,有32、24、8等。

    double t = getTickCount();
    	Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    	filter2D(src, dst, src.depth(), kernel);
    double timeconsume = (getTickCount() - t) / getTickFrequency();//获取执行时间
    	printf("tim consume %.2f\n", timeconsume);
    

Mat对象

  • Mat对象使用

    • MatB(A)

      • 复制A的图像,当A改变时,B会改变。
    • A.clone() 或 A.copyTo(B)

      • 当A改变时,B不会改变
  • cv::Mat::Mat构造函数

    • Mat M(2,2,CV_8UC3, Scalar(0,0,255))
      • 其中前两个参数分别表示行(row)跟列(column)、第三个CV_8UC3中的8表示每个通道占8位、U表示无符号、C表示Char类型、3表示通道数目是3,第四个参数是向量表示初始化每个像素值是多少,向量长度对应通道数目一致,如果少于通道数,自动补0
      • CV_64位,WINDOW_32位
    #include
    #include
    
    using namespace std;
    using namespace cv;
    
    int main() {
    	Mat src = imread("C:/Users/sualab/Downloads/image/timg.jfif");
    	if (src.empty()) {
    		cout << "not found" << endl;
    		return -1;
    	}
    	
    	//自定义图片大小、类型
    	Mat dsrc = Mat(src.size(), src.type());
    	dsrc = Scalar(4, 22, 244);
    	/*namedWindow("test", WINDOW_AUTOSIZE);
    	imshow("test", dsrc);*/
    
    	Mat dsrc00(dsrc);
    
    	Mat dsrc01 = src.clone();
    	//src.copyTo(dsrc01);
    	namedWindow("test", WINDOW_AUTOSIZE);
    	imshow("test", dsrc01);
    
    	//查看通道数
    	Mat dsrc02;
    	cvtColor(src, dsrc02,COLOR_BGR2GRAY);
    	namedWindow("test01", WINDOW_AUTOSIZE);
    	imshow("test01", dsrc02);
    	cout <<"原图像的通道数:"<< dsrc01.channels() << endl;
    	cout << "转化图像的通道数:" << dsrc02.channels() << endl;
    
    	
    	//可以自定义大小的构造方式
    	Mat dsrc04 = Mat(3, 3, CV_8UC3, Scalar(2, 45, 2));
    
    	//创建Mat,同上
    	Mat dsrc05;
    	dsrc05.create(3, 3, CV_8UC3);
    	dsrc05 = Scalar(1, 3, 2);
    	cout << "dsrc05" << dsrc05 << endl;
    
    	//获得图像的指针
    	uchar* firstRow = dsrc05.ptr(0);
    	printf("指针指向图像的第一个像素的灰度值:%d", *firstRow);//这里用cout不能获取指针的值(?)
    	/*uchar* firstRow = src.ptr(0);
    	cout << "" << *firstRow << endl;*/
    
    	//获得行数、列数
    	int rows = src.rows;
    	int cols = src.cols;
    	cout << "rows:" << rows << endl;
    	cout << "cols" << cols;
    
    	//定义小数组,(可以用来提高图片的对比度)
    	Mat kernal = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    
    	//把一个图像初始化为0(全黑)
    	//Mat::zeros(src.size(),src.type());
    	Mat m = Mat::zeros(2, 2, CV_8UC1);
    	cout << "m" << m << endl;
    	namedWindow("test02", WINDOW_AUTOSIZE);
    	imshow("test02", m);
    
    	//创建对角线为1的矩阵
    	Mat m1 = Mat::eye(2, 2, CV_8UC1);
    	
    
    	waitKey(0);
    	return 0;
    }
    

图像操作

  • 读写操作
    • 一般转为灰色的被称为单通道
    • imread 可以指定加载为灰度或者RGB图像
    • Imwrite 保存图像文件,类型由扩展名决定
  • 读写像素
    • 对一个gray像素点的像素值
      • img.at(x,y)
    • 读一个RGB像素点(通道3) 的像素值
      • Vec3f intensity = img.at(y, x);
        float blue = intensity.val[0];
        float green = intensity.val[1];
        float red = intensity.val[2];
  • 修改像素值
    • 灰度图像
      img.at(y, x) = 128;
    • RGB三通道图像
      img.at(y,x)[0]=128; // blue
      img.at(y,x)[1]=128; // green
      img.at(y,x)[2]=128; // red
    • 空白图像赋值
      img = Scalar(0);
    • ROI选择
      Rect r(10, 10, 100, 100);
      Mat smallImg = img®;
  • Vec3b与Vec3F
    • Vec3b对应三通道的顺序是blue、green、red的uchar类型数据。
      • Vec3f对应三通道的float类型数据
        把CV_8UC1转换到CV32F1实现如下:
        src.convertTo(dst, CV_32F);

图像混合

  • api
    • addWeighted
      • 参数1:图像1
      • 参数2:图像1的权重值
      • 参数3:图像2
      • 参数4:图像2的权重值,两个图像的权重和为1
      • 参数5:gamma值默认是0.0
      • 参数6:混合后的图像
  • 两张的图片的大小和类型必须一致

调整图像亮度与对比度

  • 理论

    • 图像变换

      • 像素变换 - 点操作
      • 领域操作 - 区域
        • 卷积
        • 区域计算
        • 整体特征的提取
        • 梯度的计算
        • 模式匹配
        • 焦点计算
    • 调整图像亮度和对比度属于像素变换-点操作

  • 重要的API

    • Mat new_image = Mat::zeros( image.size(), image.type() ); 创建一张跟原图像大小和类型一致的空白图像、像素值初始化为0
    • saturate_cast(val)确保值大小范围为0~255之间
    • Mat.at(y,x)[index]=value 给每个像素点每个通道赋值
    • g(i,j)= af(i,j)+b

绘制形状和文字

  • 使用Point 和Scalar

    • point 表明2d平面的一个点
    • Scalar表示4个元素的 向量
      • Scalar(a, b, c);// a = blue, b = green, c = red表示RGB三个通道
  • 绘制线、矩形、园、椭圆等基本几何形状

  • 画线 cv::line (LINE_4\LINE_8\LINE_AA(反锯齿))

  • 画椭圆cv::ellipse

  • 画矩形cv::rectangle

  • 画圆cv::circle

  • 画填充cv::fillPoly

    • fillPoly(img,ppt,npt,1,Scalar(255,255,255),lineType);

    • 函数参数:

      • 多边形将被画到img
  • 多边形的顶点集为ppt

  • 绘制的多边形顶点数目为npt

  • 要绘制的多边形数量为1

  • 多边形的颜色定义为Scarlar(255,255,255),即RGB的值为白色

    void myfillpoly() {
    	//申明一个顶点集合数组
    	Point a[1][5];
    	//五个顶点
    	a[0][0] = Point(100, 100);
    	a[0][1] = Point(100, 300);
    	a[0][2] = Point(200, 300);
    	a[0][3] = Point(200, 300);
    	a[0][4] = Point(200, 300);
    	const Point* ppt[] = { a[0] };//定一个指针集,指向各个顶点
    
    	int npt[] = { 5 };//顶点数目,因为可能有多个多边形,所以定义为数组形式
    	//第四个参数为多边形的数目
    	fillPoly(src, ppt, npt, 1, Scalar(33, 55,6, 122));
    }
    
    
    • putText()绘制文本

      void putText(
      		cv::Mat& img, // 待绘制的图像
      		const string& text, // 待绘制的文字
      		cv::Point origin, // 文本框的左下角
      		int fontFace, // 字体 (如cv::FONT_HERSHEY_PLAIN)
      		double fontScale, // 尺寸因子,值越大文字越大
      		cv::Scalar color, // 线条的颜色(RGB)
      		int thickness = 1, // 线条宽度
      		int lineType = 8, // 线型(4邻域或8邻域,默认8邻域)
      		bool bottomLeftOrigin = false // true='origin at lower left'
      	)
      
    • RNG

      • RNG可以产生3种随机数
        • RNG(int seed) 使用种子seed产生一个64位随机整数,默认-1
        • RNG::uniform( ) 产生一个均匀分布的随机数
        • RNG::gaussian( ) 产生一个高斯分布的随机数

图像模糊

  • 噪声在图像当中常表现为一引起较强视觉效果的孤立像素点或像素块。简单来说,噪声的出现会给图像带来干扰,让图像变得不清楚。

  • 均值滤波

    • 均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标像素为中心的周围8个像素,构成一个滤波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代替原来像素值。
      • 由于图像边框上的像素无法被模板覆盖,所以不做处理。
      • 3*3的9个像素值相加除以9就是中间的值
    • 由于周围的像素值都差不多,导致图像没有明显突出像素,从而变得更加模糊
    void blur(Mat src,Mat dst, Size(xradius,yradius), Point(-1, -1))
    
  • 高斯滤波

    • 高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。

      #高斯函数
      void GaussianBlur(InputArray src,      //输入图像
                  OutputArray dst,    //输出图像
                  Size ksize,       //内核的大小,size(x,y)其中xy为正数,奇数。
                  double sigmaX,     //高斯核函数在X方向的标准偏差  
                  double sigmaY=0,    //高斯核函数在Y方向的标准偏差
                  intborderType=BORDER_DEFAULT )   
      
  • 中值滤波

    • 中值,中间值,将数据从小到大排序后的中间值,赋给中间的值

    • 中值模糊的ksize大小必须是大于1而且必须是奇数。

      void medianBlur(InputArray src, OutputArray dst, int ksize)
      
  • 双边滤波

    • 均值模糊无法克服边缘像素信息丢失缺陷。原因是均值模糊是基于平均权重。

    • 高斯模糊部分克服了该缺陷,但是无法完全避免,因为没考虑到像素值的不同。

    • 双边滤波是保留边缘的滤波方法,避免了边缘信息的丢失,保留了图像轮廓不变。

      void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT 
      
      • d - 15 计算的半径,半径之内的像数都会被纳入计算,如果提供-1 则根据sigma space参数取值
      • sigmaColor -150 sigma color 决定多少差值之内的像素会被计算
      • sigmaSpace -3 如果d的值大于0则声明无效,否则根据它来计算d值
  • 中值与双边一般适合磨边美颜。

  • 参考

膨胀和腐蚀

  • 膨胀

    • b结构锚点在图像上进行卷积,找到像素值最大的进行替换
    • 相对白色比较多,而黑色相对较少
  • 腐蚀

    • b结构锚点在a图像上进行卷积,找到像素值最小的进行替换
    • 相对白色比较少,而黑丝相对较多。
    #include
    
    using namespace cv;
    
    Mat src_1,nsrc_1;
    
    //拖动条的值
    int value;
    
    void on_trackBar(int, void*);
    
    int main1_1() {
    
    	value = 1;
    	src_1 = imread("C:/Users/sualab/Downloads/image/tg.jfif");
    	namedWindow("test", WINDOW_AUTOSIZE);
    	imshow("test", src_1);
    
    	namedWindow("ntest", WINDOW_AUTOSIZE);
    	createTrackbar("bar", "ntest", &value, 100, on_trackBar);
    	on_trackBar(value, 0);//回调函数,调用定义的trackBar函数
    
    	waitKey(0);
    	return 0;
    }
    void on_trackBar(int, void*) {
    	if (value == 0) {
    		value = 1;
    	}
    	int s = value * 2 + 1;
    	Mat element = getStructuringElement(MORPH_RECT, Size(s, s));//Size为腐蚀的程度
    	//腐蚀
    	//erode(src_1, nsrc_1, element);//第三个为结构元素,第四个为锚点,默认值
    
    	//膨胀
    	dilate(src_1, nsrc_1, element);
    	imshow("ntest", nsrc_1);
    }
    

形态学操作

void morphologyEx(src, dst, int op, InputArray kernel, Point ancho, int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue())
第三个参数:选择使用什么形态学操作
           MORPH_OPEN - 开操作
           MORPH_CLOSE - 闭操作
           MORPH_GRADIENT - 形态学梯度
           MORPH_TOPHAT - 顶帽
           MORPH_BLACKHAT - 黑帽
           MORPH_HITMISS - 击中与击不中
  • 开运算

    • 先腐蚀后膨胀的过程
    • 开运算可以用来消除小物体,在纤细处分离物体,并且在平滑较大物体的边界的同时不明显改变其面积。
  • 闭运算

    • 先膨胀后腐蚀的过程
    • 运算可以填充小的黑洞。
  • 形态学梯度

    • 膨胀减去腐蚀
    • 可以将团块的边缘突出来,我们可以用形态学梯度来保留物体的轮廓
    • img
  • 顶帽

    • 原图像与开操作之间的差值,

    • 因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。

    • 顶帽运算往往用来分离比邻近点亮一些的斑块。当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取。

  • 黑帽

    • 黑帽是闭操作图像与源图像的差值图像

    • 黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关。所以,黑帽运算用来分离比邻近点暗一些的斑块。

  • 参考

提取水平线,垂直线

  • 输入图像彩色图像 imread

  • 转换为灰度图像 – cvtColor

  • 转换为二值图像 – adaptiveThreshold

  • 定义结构元素

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

    #include
    using namespace cv;
    
    //输入图像彩色图像 imread
    //转换为灰度图像 – cvtColor
    //转换为二值图像 – adaptiveThreshold
    //定义结构元素
    //开操作 (腐蚀 + 膨胀)提取 水平与垂直线
    
    
    int main1_3() {
    	Mat src = imread("C:/Users/sualab/Pictures/test.png");
    	Mat gray_src,nsrc;
    
    	//转为灰度
    	cvtColor(src, gray_src, COLOR_BGR2GRAY);
    
    	//转为二值图像
    
    	//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,负数
    	//)
    	imshow("test3", gray_src);
    
    	adaptiveThreshold(~gray_src, nsrc, 255,ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
    
    	//定义结构元素
    	
    	//定义矩形元素
    	Mat kernal = getStructuringElement(MORPH_RECT, Size(3, 3));
    	//定义水平元素
    	Mat xline = getStructuringElement(MORPH_RECT, Size(1, src.rows / 16));
    	//定义垂直元素
    	Mat yline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1));
    
    	Mat nnsrc;
    	Mat nnnsrc;
    
    	/*erode(nsrc, nnsrc, xline);
    	dilate(nnsrc, nnnsrc, xline);*/
    
    	//morphologyEx(src, nnsrc, MORPH_OPEN, kernal);效果如上所示
    
    	/*erode(nsrc, nnsrc, yline);
    	dilate(nnsrc, nnnsrc, yline);*/
    
    	erode(nsrc, nnsrc, kernal);
    	dilate(nnsrc, nnnsrc, kernal);
    
    	imshow("ntest", nnnsrc);
    
    	waitKey();
    	return 0;
    
    }
    

基本阈值操作

  • 图像的二值化

    • 就是把图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现明显的黑和白的视觉效果
    • 一幅图像包括目标物体、背景还有噪声,要想从多值的数字图像中直接提取出目标物体,常用的方法就是设定一个阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群。这是研究灰度变换的最特殊的方法,称为图像的二值化(Binarization)。
  • 阈值类型

    • threshold(img, threshold, maxval,type)

      • threshold是设定的阈值
      • maxval是当灰度值大于(或小于)阈值时将该灰度值赋成的值
      • type规定的是当前二值化的方式
    • THRESH_BINARY

      • 大于阈值的部分被置为255,小于部分被置为0
    • THRESH_BINARY_INV

      • 大于阈值的部分被置为0,小于部分被置为255
    • THRESH_TRUNC

      • 大于阈值部分被置为threshold,小于部分保持原样
    • THRESH_TOZERO

    • 小于阈值部分被置为0,大于部分保持不变

    • **THRESH_TOZERO_INV **

      • 大于阈值部分被置为0,小于部分保持不变
  • 参考

自定义线性滤波

  • 卷积概念

    • 卷积是图像处理中一个操作,是kernal在图像的每个像素上的操作。

    • kernal本质上是一个固定的矩阵数组,其中心点称为锚点(anchor point)

    • 算子

      • -1 1 -1

        -1 5 -1

        -1 1 -1

你可能感兴趣的:(OpenCV,opencv基础)