Opencv 图片处理
目录
一,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);
本地文件:
windows自带软件显示是宽582像素,高266像素
我的程序运行结果:
文件名还有bug,连英文字母都乱码了。
如果读取参数是IMREAD_GRAYSCALE,那么显示的结果:
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;
-
}
输出:
2,Range
Range的2个参数就是坐标的区间范围
Mat image2 = image(Range(0,200),Range(50,400));
第一个Range是选择行的范围,第二个是选择列的范围。
就感觉两种方式的参数顺序的反的!
四,图片尺寸 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);
五,窗口控制 namedWindow
namedWindow("1", WINDOW_GUI_NORMAL);
第二个参数是用来控制窗口的属性,主要是位置和尺寸能否改变。
加上这句话之后,会多显示一个黑框,imshow输出的窗口也能移动了。
否则,imshow输出的窗口是不能移动的。
这个结果有点奇怪,我理解namedWindow函数应该就是用来控制imshow输出的窗口的属性才对。
文章来源: blog.csdn.net,作者:csuzhucong,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/nameofcsdn/article/details/118256071
- 点赞
- 收藏
- 关注作者
评论(0)