目录

​一,Mat类、图像核心信息​

​1,客观信息​

​(1)维数​

​(2)行列​

​2,主观信息​

​(1)通道数​

​(2)位深​

​3,Mat类坐标​

​二,基本操作​

​1,读取 imread​

​2,读取类型 ImreadModes​

​3,显示读取结果 imshow​

​4,显示信息​

​5,存储图像​

​三,图片截取​

​1,Rect​

​2,Range​

​四,图片尺寸 resize​

​五,窗口控制 namedWindow​


一,Mat类、图像核心信息

Mat类用一个对象对应一张图,除了数据域还有各种重要信息。

1,客观信息

一张图片有多少像素,每个像素的坐标,都是客观信息。

(1)维数

成员dims是维数,当维数是2时,成员rows和cols才有意义

(2)行列

成员rows和cols即行列信息

2,主观信息

每个像素点有什么信息,是主观信息。

(1)通道数

每个像素点采用几个通道存储,就是通道数,这取决于模型。

成员函数channels()是获取通道数,最常见的就是1和3

(2)位深

每个像素点的每个通道用多少位来存,即位深。

成员函数depth()是获取深度,是枚举值,最常见的就是CV_8U  

#define CV_8U   0

#define CV_8S   1

#define CV_16U  2

#define CV_16S  3

#define CV_32S  4

#define CV_32F  5

#define CV_64F  6

#define CV_16F  7

后缀表示数据类型,U unsigned   S signed  F float

3,Mat类坐标

Mat类中默认的坐标是以左上角为原点,向下和向右是正方向。

至于哪个是x,哪个是y,Mat中两种坐标都用到。

而行和列这2个词应该是没有歧义的,所以有些地方我会用行坐标和列坐标来描述。

4,Mat对象创建

可以读取图片文件创建Mat对象,也可以用数组创建Mat对象

char c[] = "123456789";
int row = 3, col = 3;
Mat image = Mat(row, col, CV_8U, c);

5,Mat类型转换

修改Mat对象的值,原数组的值会改变。

int main()
{
char c[] = "123456789";
int row = 3, col = 3;
Mat image = Mat(row, col, CV_8U, c);
image.at<char>(1, 1) = 56;
for(int i=0;i<9;i++)cout << (c[i])<<" ";
return 0;
}

输出:1 2 3 4 8 6 7 8 9

如果把8位图像转成32位图像,会重新分配内存:

int main()
{
char c[] = "123456789";
int row = 3, col = 3;
Mat image = Mat(row, col, CV_8U, c);
image.convertTo(image, CV_32F);
image.at<float>(1, 1) = 56;
for(int i=0;i<9;i++)cout << (c[i])<<" ";
return 0;
}

输出:1 2 3 4 5 6 7 8 9

即使是CV_32S转成CV_32F 也是一样,会重新分配内存。

二,基本操作

1,读取 imread

string path = "D:/im2.jpg";
Mat image = imread(path, IMREAD_UNCHANGED);
if (!image.data) {
cout << "imread fail\n";
return;
}

第二个参数是ImreadModes类型的枚举,表示读取的通道数

返回的是一个Mat类型的对象。

成员data是uchar的指针,如果读取失败那么指针为空

2,读取类型 ImreadModes

ImreadModes的源代码:

enum ImreadModes {
IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). Ignore EXIF orientation.
IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion).
IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image.
IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format.
IMREAD_LOAD_GDAL = 8, //!< If set, use the gdal driver for loading the image.
IMREAD_REDUCED_GRAYSCALE_2 = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2.
IMREAD_REDUCED_COLOR_2 = 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.
IMREAD_REDUCED_GRAYSCALE_4 = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4.
IMREAD_REDUCED_COLOR_4 = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
IMREAD_REDUCED_GRAYSCALE_8 = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
IMREAD_REDUCED_COLOR_8 = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag.
};

-1 IMREAD_UNCHANGED 表示按照图片本身的通道数

0 IMREAD_GRAYSCALE 表示灰度图像,即单通道

1 IMREAD_COLOR 表示按照3通道

3,显示读取结果 imshow

imshow("img", image);
waitKey(0);

本地文件:

Opencv 图片处理_#define

windows自带软件显示是宽582像素,高266像素

我的程序运行结果:

Opencv 图片处理_像素点_02

文件名还有bug,连英文字母都乱码了。

如果读取参数是IMREAD_GRAYSCALE,那么显示的结果:

Opencv 图片处理_i++_03

4,显示信息

打印每个像素点的像素值:

cout << "rows=" << image.rows << endl;
cout << "cols=" << image.cols << endl;
cout << "channels=" << image.channels() << endl;

for (int i = 0; i < image.rows; i++) {
for (int j = 0; j < image.cols; j++) {
cout << int(image.at<Vec3b>(i, j)[0])<<" ";
}
cout << endl;
}

at是模板函数,返回值类型就是模板参数的类型。

如类型参数Vec3b对应三通道的图,返回的就是Vec3b,它是一个长为3的向量,获取其中一个通道的像素值可以用[0]、[1]、[2],类型是uchar,转化成int就是0-255

其实有Vec3i的类型,直接就是int类型,但是用这个直接报内存错误,不知道为啥。

如果是单通道的图,那么参数类型就是uchar:

for (int i = 0; i < image.rows; i++) {
for (int j = 0; j < image.cols; j++) {
cout << int(image.at<uchar>(i, j))<<" ";
}
cout << endl;
}

5,存储图像

简单写法:

imwrite("D:/im2.jpg", image2);

第三个参数缺省了。

三,图片截取

1,Rect

初始化Rectangle矩形对象,依次提供四个参数:列坐标,行坐标,宽度,高度

int main()
{
string path = "D:\im.jpg";
Mat image = imread(path, IMREAD_COLOR);
namedWindow("1", WINDOW_GUI_NORMAL);

Rect area(0, 50, 200, 350);
Mat image2 = image(area);
imshow("img", image);
imshow("img2", image2);
waitKey(0);
return 0;
}

输出:

Opencv 图片处理_#define_04

2,Range

Range的2个参数就是坐标的区间范围

Mat image2 = image(Range(0,200),Range(50,400));

第一个Range是选择行的范围,第二个是选择列的范围。

Opencv 图片处理_像素点_05

就感觉两种方式的参数顺序的反的!

四,图片尺寸 resize

先给出要变成的大小,Size类根据(宽度,高度)生成对象,

然后用resize函数得到一个新尺寸的Mat对象,原对象不影响。

resize的第五个参数是插值算法的类型。

Size dsize = Size(round(0.3 * image.cols), round(0.6 * image.rows));
Mat shrink;
resize(image, shrink, dsize, 0, 0, INTER_AREA);
imshow("shrink", shrink);
waitKey(0);

Opencv 图片处理_i++_06

五,窗口控制 namedWindow

namedWindow("1", WINDOW_GUI_NORMAL);

第二个参数是用来控制窗口的属性,主要是位置和尺寸能否改变。

加上这句话之后,会多显示一个黑框,imshow输出的窗口也能移动了。

否则,imshow输出的窗口是不能移动的。

这个结果有点奇怪,我理解namedWindow函数应该就是用来控制imshow输出的窗口的属性才对。