OpenCV从入门到放弃(三):Core组件细讲

来源:互联网 发布:linux 小数比较大小 编辑:程序博客网 时间:2024/05/01 20:25

Core组件由名字就知道是最核心功能的模块:在Core组件中,包含了最基本的数据结构,动态数据结构,画图的一些函数和一些系统函数.下面依次来讲一下这些基本的功能.Core组件是很重要的相当于修楼房的砖块,要把一些基本的概念弄懂.

一:基本数据结构

1.Mat类(最基本的数据结构)

1.概念

1.Mat不仅仅是一个图像容器类,同时也是一个通用的矩阵类.2.不必再手动为其开辟空间,也不必在不需要的时候立即将他的空间释放3.Mat是一个类,由两个数据部分组成:    1.矩阵头:矩阵尺寸,存储方法,存储地址等等所有相关信息(矩阵头的尺寸是常数值)    2.指向存储所有像素值数据块的指针.4.赋值运算符和复制构造函数只会复制信息头和指向数据块指针的值.但是不会完整的复制一个矩阵(为了性能和避免内存溢出考虑).所以有多个对象引用同一个值矩阵,改变其中一个对象有改变其他的对象的可能.5.使用clone()或者copyTo()来深层复制一幅图像的矩阵.       6.前面已经知道一个矩阵可以被多个Mat对象引用,那么最后一个使用这个矩阵的对象,负责清理矩阵。 

2.常用函数

1.构造函数(主要介绍下面这两种)

Mat (int rows, int cols, int type, const Scalar &s)    Rows:行数    Cols:列数    Type:类型 CV_[位数][带符号与否][类型前缀][通道数]        例:CV_8UC3表示使用8位的unsighed char类型.每个像素由三个元素组成的三通道.    类型汇总:    CV_8U  (8 bit 无符号整形0~255)    CV_8UC1 (1通道)  CV_8UC2 (2通道)  CV_8UC3 (3通道)  CV_8UC4(4通道)     CV_8S   (8 bit有符号整形-128~127)    CV_8SC1 (1通道)  CV_8SC2 (2通道)   CV_8SC3 (3通道)  CV_8SC4 (4通道)       CV_16U  (16 bit 无符号整形0~65535)    CV_16UC1 (1通道)  CV_16UC2 (2通道)   CV_16UC3 (3通道)   CV_16UC4 (4通道)       CV_16S  (16 bit 有符号整形-32768~32767)    CV_16SC1(1通道)   CV_16SC2(2通道)   CV_16SC3(3通道)   CV_16SC4(4通道)       CV_32S  (32 bit 有符号整形-2147483648~2147483647)    CV_32SC1   CV_32SC2    CV_32SC3  CV_32SC4       CV_32F  (32 bit 浮点)    CV_32FC1   CV_32FC2  CV_32FC3   CV_32FC4      CV_64F   (64 bit 浮点)    CV_64FC1   CV_64FC2  CV_64FC3  CV_64FC4      Scalar:颜色类..具体看下面的Scalar类.Mat (int ndims, const int *sizes, int type, const Scalar &s)    Ndims:维数.    *size:一个数组,表示相应维数下面的具体数量    Type:和上面一样    Scalar:和上面一样.

2.empty()函数(判断是否Mat是否有元素,或者是否分配了图像数据)

使用方法:Mat对象.empty()返回一个bool对象.

3.channels()函数

返回一个Mat对象的通道数.

4.create()函数

这个方法不能够为矩阵设置初值,只是在改变尺寸的时候重新为矩阵开辟内存而已.

5.type()函数 返回的是一个int值.返回mat的类型.

3.例子

1.Mat的初始化和输出

我们在这里使用的初始化是标准的Mat()构造函数的方法,输出方法是Python风格的输出(以后也会固定这样的创建和输出风格.)
这里写图片描述
这里写图片描述
按照pyton的方式输出矩阵,同时还有一点点红色出现在框里面.这是矩阵的输出方式.

2.Mat的内存管理方式(这个例子非常重要)

代码:
这里写图片描述
这里写图片描述

结果及其分析:
1.首先就一整个来说,
这里写图片描述
因为namewindow()了六个窗口.但是其中有一个”image”窗口变色了.
这里写图片描述
是因为上面这段代码初始化了一个灰度图(CV_8U)然后在”image”命名的这个窗口显示导致的.

2.按一下回车.
其他都没有变,那个image窗口变小了,而且颜色也变了.
这里写图片描述
是因为下面这段代码导致的
这里写图片描述
也就是说.这个时候的image1这个mat对象被重新改变了size和值.

3.按一下回车
这里写图片描述
其他的没有变,只有“image”这个窗口变了。是下面这段代码改变的。
这里写图片描述
这段代码新建了一个image2的mat对象,并且是三通道彩色的(CV_8UC3)。初始的值设为红色。然后Image这个窗口用来显示image2这个对象了。(这个例子说明。一个窗口用了之后还能够给其他的对象再用。)

4.按一下回车
这里写图片描述
这次改变就蛮大了.
这里写图片描述
上面这段代码先是建立了一个image3的对象,并且都载入了一张图像
原图是这个样子的
这里写图片描述
然后就浅复制给image4,然后就深复制给image5.然后image3翻转。
我们看到,image4和image3都翻转了。但是image5没有翻转。因为image5是深度复制变得独立。不受image3翻转的影响

5.按一下回车
这里写图片描述
Image窗口变成灰色,
这里写图片描述

得到的结论是:
1.可以随时用create方法分配或者重新分配图像的数据块,要是图像已经分配,首先其原来的内容会被释放。(要是新的大小和类型都与原来的相同,就不会重新分配内存)
2.一旦没有了指向cv::Mat对象的引用,那么这个对象就会被自动释放。
3.在两个图像之间赋值的时候(包括赋值=或者复制构造函数等等),图像数据并不会被复制,此时两个图像都指向同一个内存块。所以,这样的出来的图像有可能会影响到其他的图像
4.要想深度复制图形的话,可以用copyTo()方法或者clone()方法。
5.如果你需要把一个图像复制到另外一个图像中,但是两者的数据类型是不一样的,那么就要是用convertTo方法

2.Scalar类(颜色表示)

1.概念

1.Scalar类源头为scalar_类,typedef  Scalar_< double >     cv::Scalar后成为scalar类2.Scalar表示具有4个元素的数组,一般在OpenCV中被用来传递像素值.

2.函数

就举一个简单的构造函数

cv::Scalar_< _Tp >::Scalar_     ( _Tp  v0,_Tp  v1,_Tp  v2 = 0,_Tp  v3 = 0 )     

3.用法

一般的用法就是Scalar(a,b,c)表示一个颜色对象.注意:顺序分别是蓝,绿,红.在上面Mat的构造函数中就有Scalar的使用.回过头来看一下是不是豁然开朗?

3.Point类(点的表示)

1.概念

Point类表示二维坐标系下面的点.

2.函数

举两个常用的构造函数

Point_ (_Tp _x, _Tp _y)   //代入坐标Point_ (const Point_ &pt)  //代入点

3.用法

Point p=Point(1,2)   //p就表示一个坐标(1,2)的点等价于Point p;p.x=1;p.y=2;

4.Size类(尺寸的表示)

1.概念

就是表示尺寸的一个类,来源于Size_()

2.函数

Size_ (_Tp _width, _Tp _height)其实就是宽和高

3.用法

Size(3,4)   //宽和高分别是3,4

5.Rect类(矩形的表示)

1.概念

表示一个矩形的类,来源是Rect_< _Tp >

2.函数

常用的构造函数:Rect_ (_Tp _x, _Tp _y, _Tp _width, _Tp _height) //传坐标和宽高Rect_ (const Rect_ &r)       //传rect对象Rect_ (const Point_< _Tp > &org, const Size_< _Tp > &sz)  //传入点(得到坐标)尺寸(得到宽高)普通函数_Tp  area () const    //返回矩形面积Point_< _Tp >  br () const   //返回右下角点坐标bool  contains (const Point_< _Tp > &pt) const   //判断某点是否在矩形内Size_< _Tp >    size () const   //返回当前矩形的SizePoint_< _Tp >  tl () const  //返回左上角点坐标

3.用法

就这么用…

二.绘图函数

首先要讲一下,接下来的大部分函数都在cv::LineIterator这个类下面.画直线等等函数在imgproc这个模块中.之所以放在Core这个组件讲,是因为前面刚刚讲了Opencv中的一些基本的数据结构.绘图函数本身也是十分重要的函数且用到之前讲过的概念.因此,提前放在这里讲.下面是绘图函数的官方文档.
http://docs.opencv.org/master/d6/d6e/group__imgproc__draw.html#ga7078a9fae8c7e7d13d24dac2520ae4a2

1.直线(line)

1.函数及其使用方式

void cv::line   ( InputOutputArray  img,            Point   pt1,            Point   pt2,            const Scalar &      color,            int     thickness = 1,            int     lineType = LINE_8,            int     shift = 0     )     Img:待操作的图片    pt1:起点    Pt2:终点    Color:颜色    Thickness:厚度(粗细)    LineType:直线类型    Shift:  

2.实例

代码:

#include <iostream>#include <opencv2/core.hpp>#include <opencv2/highgui.hpp>//画直线等等函数在imgproc中#include <opencv2/imgproc.hpp>  int main(){    //创建一个窗口并且以Tset为标示    cv::namedWindow("Test");    //创建空白的图像    cv::Mat Image = cv::Mat::zeros(600, 600, CV_8UC3);    //起点和终点    cv::Point p1(100, 200);    cv::Point p2=cv::Point(100, 400);    cv::Point p3(150, 200);    cv::Point p4 = cv::Point(150, 400);    cv::Point p5(200, 200);    cv::Point p6 = cv::Point(200, 400);    cv::Point p7(250, 200);    cv::Point p8 = cv::Point(250, 400);    //画直线1    cv::line(Image, p1, p2, cv::Scalar(0, 0, 255), 1, 8, 0);    //画直线2(改变了线条粗细)    cv::line(Image, p3, p4, cv::Scalar(0, 0, 255), 10, 8, 0);    //画直线3(改变了线条类型)    cv::line(Image, p5, p6, cv::Scalar(0, 0, 255), 1, 4, 0);    //画直线4(改变了shift)    cv::line(Image, p7, p8, cv::Scalar(0, 0, 255), 1, 8, 0);    cv::imshow("Test", Image);    cv::waitKey(0);    return 0;}

效果:
这里写图片描述

2.椭圆(ellipse)

1.函数使用方式

void cv::ellipse    ( InputOutputArray      img,                Point   center,                Size    axes,                double      angle,                double      startAngle,                double      endAngle,                const Scalar &      color,                int     thickness = 1,                int     lineType = LINE_8,                int     shift = 0     )    Img:待操作的图片    Center:椭圆中心点坐标    Axes:是一个size的类型,其实就是长短轴的大小(最终肯定是位于一个矩形框里面)    Angle:表示椭圆的旋转角度    startAngle:开始扩展弧度    endAngle:结束的扩展弧度    Color:颜色    Thickness:厚度(粗细)    LineType:线类型    Shift:  

2.实例

代码:

#include <iostream>#include <opencv2/core.hpp>#include <opencv2/highgui.hpp>//画直线等等函数在imgproc中#include <opencv2/imgproc.hpp>  int main(){    //创建一个窗口并且以Tset为标示    cv::namedWindow("Test");    //创建空白的图像    cv::Mat Image = cv::Mat::zeros(600, 600, CV_8UC3);    //中心点和长短轴    cv::Point c1(100, 200);    cv::Size ax1(50, 100);    cv::Point c2(250, 200);    cv::Size ax2(50, 100);    cv::Point c3(400, 200);    cv::Size ax3(50, 100);    //画椭圆1,中心(100,200),短轴50,长轴100,旋转角度为0°,扩展弧长为(0,360)    //颜色,粗细等等可以类比前面讲过的直线    cv::ellipse(Image, c1, ax1, 0, 0, 360, cv::Scalar(0, 0, 255), 1, 8, 0);    //画椭圆2,中心(250,200),短轴50,长轴100,旋转角度为30°,扩展弧长为(0,360)    //颜色,粗细等等可以类比前面讲过的直线    cv::ellipse(Image, c2, ax2, 30, 0, 360, cv::Scalar(0, 0, 255), 1, 8, 0);    //画椭圆3,中心(400,200),短轴50,长轴100,旋转角度为30°,扩展弧长为(90,360)    //颜色,粗细等等可以类比前面讲过的直线    cv::ellipse(Image, c3, ax3, 30, 90, 360, cv::Scalar(0, 0, 255), 1, 8, 0);    cv::imshow("Test", Image);    cv::waitKey(0);    return 0;}

效果:
看了效果之后,应该对于这个椭圆的各个角度应该有了认识.
这里写图片描述

3.矩形(rectangle)

1.函数使用方式

方式一:void cv::rectangle  ( InputOutputArray  img,                Point  pt1,                Point  pt2,                const Scalar &  color,                int  thickness = 1,                int  lineType = LINE_8,                int  shift = 0         )       Img:待操作的图片    pt1:顶点坐标    Pt2:对角线那个顶点的坐标    Color:颜色    Thickness:厚度(粗细)    LineType:线类型    Shift:  方式二:void cv::rectangle  ( Mat &  img,                Rect  rec,                const Scalar &  color,                int  thickness = 1,                int  lineType = LINE_8,                int  shift = 0         )       Img:待操作的图片    Rec:矩阵对象    Color:颜色    Thickness:厚度(粗细)    LineType:线类型    Shift:  

2.实例

代码:

#include <iostream>#include <opencv2/core.hpp>#include <opencv2/highgui.hpp>//画直线等等函数在imgproc中#include <opencv2/imgproc.hpp>  int main(){    //创建一个窗口并且以Tset为标示    cv::namedWindow("Test");    //创建空白的图像    cv::Mat Image = cv::Mat::zeros(600, 600, CV_8UC3);    //两个顶点的方式创建矩形框    cv::Point p1(100, 200);    cv::Point p2(300, 400);    cv::rectangle(Image, p1, p2, cv::Scalar(0, 0, 225), 1, 8, 0);    //rect的方式创建矩形框    cv::rectangle(Image, cv::Rect(300, 300, 100, 200), cv::Scalar(255, 0, 0), 1, 8, 0);    cv::imshow("Test", Image);    cv::waitKey(0);    return 0;}

结果:
这里写图片描述

4.圆(circle)

1.函数使用方式

void cv::circle     ( InputOutputArray      img,            Point   center,            Int     radius,            const Scalar &      color,            int     thickness = 1,            int     lineType = LINE_8,            int     shift = 0     )       Img:待操作的图片    center:中心点坐标    Radius:半径    Color:颜色    Thickness:厚度(粗细)    LineType:线类型    Shift:  

2.实例

代码:

#include <iostream>#include <opencv2/core.hpp>#include <opencv2/highgui.hpp>//画直线等等函数在imgproc中#include <opencv2/imgproc.hpp>  int main(){    //创建一个窗口并且以Tset为标示    cv::namedWindow("Test");    //创建空白的图像    cv::Mat Image = cv::Mat::zeros(600, 600, CV_8UC3);    //创建圆    cv::Point c1(100, 200);    cv::circle(Image, c1, 50, cv::Scalar(0, 0, 255), 1, 8, 0);    cv::imshow("Test", Image);    cv::waitKey(0);    return 0;}

结果:
这里写图片描述

1 0