载入、显示及保存图像

表示图像的类型:
cv::Mat
相关函数:
imread():读取图像,输入参数为文件名称
namedWindow():定义需要显示图像的窗口,输入参数为窗口的名称
imshow():显示图像,输入参数1为用于显示的窗口名称,参数2为要显示的图像变量
imwrite():保存图像,输入参数1为保存以后图像的名称,后缀名决定了保存格式,参数2为要保存的图像变量
代码如下:

cv::Mat image;
image=cv::imread("img.jpg");
if(!image.data)     //data变量指向图像数据所在内存指针,当不存在数据时,该变量为0
{
//此处添加无法读取图片的代码
}
cv::Mat result;
image.copyTo(result);//复制图像image传递给result
cv::namedWindow("Output Image");
cv::imshow("Output Image",result);
cv::imwrite("output.bmp",result);

如果在main函数中加入代码 using namespace cv 就不需要在函数前面加命名空间cv::了

说明

cv::Mat类型是用于保存图像和其他矩阵数据的数据结构,该类型就是保存一个像素矩阵,每一个元素代表一个像素,像素具有不同的类型,因此矩阵的每一个元素有可能是一个字节,比如说类型为CV_8U,此时矩阵的每个元素都是无符号单字节,用于表示灰度图像,也有可能每个元素是一个向量,比如说类型为CV_8UC3,此时每个元素有3个字节的向量,可以用于表示彩色RGB图像,向量中的3个字节分别表示R、G、B三个通道的值。

注意:
cv::Mat使用了引用计数和浅拷贝技术,当图像变量之间赋值时,并没有开辟新的内存块,两个对象都是指向同一块内存,如果其中一个变量数据改变,另一个也会随之改变,变量内部有一个引用计数,用于记录指向这块内存的对象的个数,当所有引用该内存数据的对象都被析构了,才会释放内存块。

发生浅拷贝的情况:

  • 函数传递参数
  • 函数返回值传值
  • 直接赋值

发生深拷贝的情况:

  • copyTo函数
  • clone函数

另外,在实际的编写一个图像处理的函数时,应该避免直接返回图像,因为如果在类函数中返回了类的图像成员,那么如果返回值发生了改变,类的图像成员也会发生改变,通常我们编写图像处理函数时的方法是:允许用户输入一个源对象和目标对象,如果不需要改变源对象,则输入源对象参数的方法使用常量引用的方法,处理后图像保存在目标对象中,这样就避免了返回图像对象,伪代码如下:

void Example(const cv::Mat &image,cv::Mat &result)
{
	result.create(iamge.size(),image.type());
	//相关的处理操作
}

create函数检查输出图像与输入图像的大小和元素数据类型是否一致,如果不一致,该函数会根据新的尺寸和数据类型对矩阵进行重新分配,如果一致,则create函数会直接返回。
注意:create函数创建的图像内存都是连续的,不会对图像的行进行填补。

操作像素值

灰度图:

image.at<uchar>(i,j)

彩色图

image.at<cv::Vec3b>(i,j)[0]  //红色通道
image.at<cv::Vec3b>(i,j)[1]  //绿色通道
image.at<cv::Vec3b>(i,j)[2]  //蓝色通道

使用模板函数at是必须要指定数据类型,该类型要与cv::Mat的数据类型一致,例如cv::Vec3b代表三个8位二进制数组成的向量,正好对应矩阵的CV_8UC3类型。