OpenCV
是一个计算机视觉库,其主要重点是处理和操作图像数据。因此需要熟悉的第一件事是 OpenCV
如何存储和处理图像。由上一篇博客: 数字图像处理基础与OpenCV中的图片读写 可以知道,图像在计算机中的存储方式其实就是数组矩阵。
2000年6月,第一个开源版本OpenCV alpha 3
发布,那个时候的OpenCV
是围绕C语言接口构建的,为了将图像存储在内存中,OpenCV
使用了称为IplImage
的C语言结构体。这也将C语言的所有缺点都带到了台面上,比如比较显著的问题之一是手动内存管理。
在OpneCV 2.0
之后的C++
库中,图像都用Mat
对象来存储,该接口提供了一种新的处理方式。这意味着在使用C++ OpenCV
时无需费心处理内存管理,不再需要手动分配其内存并在不需要时立即释放它。
Mat
对象本质上是具有两个数据部分的类:
- 矩阵头,包含诸如矩阵大小,用于存储的方法,用于存储矩阵的地址之类的信息等等。
- 指向存储像素值矩阵的指针,根据选择的图像存储方法可以保存成任何维度的数组。
矩阵头的大小是恒定的,但是矩阵本身的大小可能因图像而异,通常会增加几个数量级。
Mat
对象常用构造函数:
Mat::Mat(); //默认构造函数
Mat::Mat(int rows, int cols, int type); //指定类型的二维数组
Mat::Mat(Size size, int type); //指定类型的二维数组
Mat::Mat(int rows, int cols, int type, const Scalar& s); //指定类型的二维数组,并指定初始化值
Mat::Mat(Size size, int type, const Scalar& s); //指定类型的多维数组,并指定初始化值
Mat::Mat(const Mat& m); //复制构造函数,深拷贝
Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP); //指定类型的二维数组,并指定预先存储的数据
Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP); //指定类型的多维数组,并指定预先存储的数据
Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange); //从指定行列中复制数据
Mat::Mat(const Mat& m, const Rect& roi); //从ROI中复制数据
克隆和复制对应C++
中的深拷贝,即与原图片有不同的数据块。而直接赋值对应C++
中的浅拷贝,即与原图片占有同一块数据块。
mat_create_and_assignment.cpp:
Mat input_image = imread("test_images/opencv.jpg",1);
//克隆:与原图片占有不同data block
Mat clone_img = input_image.clone();
imshow("clone", clone_img);
//复制:与原图片占有不同data block
Mat copy_img;
input_image.copyTo(copy_img);
imshow("copy", copy_img);
//直接赋值:与原图同一块data block
Mat assign_img = input_image;
imshow("assign", assign_img);
mat_create_and_assignment.cpp:
//创建空白图像
Mat empty_1 = Mat::zeros(input_image.size(), input_image.type());
imshow("empty_1", empty_1);
//自定义大小 Size()
Mat empty_2 = Mat::zeros(Size(512,512), input_image.type());
imshow("empty_2", empty_2);
Mat empty_3 = Mat::ones(Size(512, 512), CV_8UC3);
imshow("empty_3", empty_3);
在使用自定义滤波器时常常需要自定义卷积核,这里可以使用运算符<<
重载的方式来创建一个卷积核,卷积核本身也是一个矩阵,因此也可以跟图像数据一样用Mat对象来表示。
创建一个3x3的卷积核 mat_create_and_assignment.cpp:
[ 0 − 1 0 − 1 5 − 1 0 − 1 0 ] \begin{bmatrix} 0&-1&0\\ -1&5&-1\\ 0&-1&0\\ \end{bmatrix} ⎣⎡0−10−15−10−10⎦⎤
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
NumPy(Numerical Python)
是 Python
语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。ndarray
是NumPy
中的一个功能和性能都十分强大的N维数组对象,之前说过图像在计算机内存中就是数组,这使得ndarray
与图像数据契合。
NmuPy
的官网在 https://www.numpy.org.cn/ ,在上面可以详细地了解这个库。
因为Python API
中图像存储借助于numpy
的ndarray
,因此进行图像赋值等操作时其实使用的是numpy ndarray
带有的相关方法,因此除了导入cv2
,还需要导入numpy
这个库。
import cv2 as cv
import numpy as np
input = cv.imread("./test_images/opencv.jpg",0)
clone_image = np.copy(input)
ass_image = input
em_image = np.zeros(input.shape,input.dtype)
kernel = np.array([[0, -1, 0],[-1, 5, -1],[0, -1, 0]])
print(kernel.shape) # 3x3