OpenCV学习之路(五) 图像的载入、显示和输出

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dashujua/article/details/82260651

目录

 

图像的载入与显示

输出图像到文件

综合实例代码

滑动条的创建和使用

鼠标操作


图像的载入与显示

imread() 函数和 imshow() 函数完成了最简单的图像载入和显示。

1. imread() 函数。原型如下:

Mat imread(const string& filename, int flags = 1);

(1)第一个参数,const string& 类型的 filename,对应需要载入的图片路径名。

(2)第二个参数,int 类型的 flags,为载入标识,指定一个加载图像的颜色类型。默认值为1,代表彩色图像。有如下枚举值:

CV_LOAD_IMAGE_UNCHANGED———等价取值为-1,新版本的OpenCV中将其废置,忽略。

CV_LOAD_IMAGE_GRAYSCALE———等价取值为0,始终将图像转换成灰度再返回。

CV_LOAD_IMAGE_COLOR——等价取值为1,始终将图像转到彩色再返回。

CV_LOAD_IMAGE_ANYDEPTH——等价取值为2,若载入图像的深度为16或32则返回对应深度的图像,否则将转为8位图像再返回。

输入有冲突的标志,将使用较小的数字值。比如CV_LOAD_IMAGE_COLOR|CV_LOAD_IMAGE_ANYCOLOR将载入三通道图像。如果想载入最真是无损的原图像,可以选择CV_LOAD_IMAGE_ANYDEPTH|CV_LOAD_IMAGE_ANYCOLOR。

因为 flags 是 int 类型的变量,若我们不适用固定的枚举值,可以做如下判定:

flags > 0 返回一个 3 通道的彩色图像(解码后的图像会以BGR的通道顺序进行存储,即蓝、绿、红);

flags = 0 返回灰度图像;

flags < 0 返回包含 Alpha 通道的加载图像(默认情况下不包含 Alpha 通道)。

imread("cat.jpg", 2 | 4); //载入无损的源图像

imread("cat.jpg", 0); //载入灰度图

imread("cat.jpg", 199); //载入 3 通道的彩色图像

 

2. imshow() 函数。原型如下:

void imshow(const string& winname, InputArray mat);

(1)第一个参数,const string& 类型的 winname,为需要显示的窗口标识名称。

(2)第二个参数,InputArray 类型的 mat,为需要显示的图像。

imshow() 函数用于在指定的窗口中显示图像。若窗口是用 CV_WINDOW_AUTOSIZE(默认值)标志创建的,那么将显示图像原始大小。否则,将图像进行缩放以适应窗口。imshow() 函数缩放图像,取决于图像的深度;

如果载入的图像是 8 位无符号类型,则显示图像本来的样子。

如果图像是 16 位无符号数类型或 32 位整型,则用像素值除以 256,值的范围从 [0,256*256] 映射到 [0,255]。

如果图像是 32 位浮点型,像素值乘以 255。值的范围从 [0,1] 映射到 [1,255]。

3. namedWindow() 函数。原型如下:

void namedWindow(const string& winname, int flags = WINDOW_AUTOSIZE);

(1)第一个参数,const string& 类型的 winname,为窗口名称。

(2)第二个参数,int 类型的 flags,为窗口标识,有如下几种值:

WINDOW_NORMAL,用户可以改变窗口的大小(没有限制)。

WINDOW_AUTOSIZE,窗口会自动调整大小以适应所显示的图像,且用户不能手动改变窗口大小。

WINDOW_OPENGL,窗口创建的时候会支持 OpenGL。

输出图像到文件

1. imwrite() 函数。原型如下:

bool imwrite(const string& filename, InputArray img, const vector<int>& params=vector<int>());

(1)第一个参数,const string& 类型的 filename,为将要写入的文件名。注意要带上后缀,如:"dog.jpg"。

(2)第二个参数,InputArray 类型的 img,一般为 Mat 类型的图像数据。

(3)第三个参数,const vector<int>& 类型的 params,为特定格式保存的参数编码。默认值为 vector<int>()。若要给定值,有以下需要注意的地方:

对于 JPEG 格式的图像,该参数表示从0 到 100 的图像质量(CV_IMWRITE_JPEG_QUALITY),默认值是95。

对于 PNG 格式的图像,该参数表示从0 到 9压缩级别(CV_IMWRITE_PNG_COMPRESSION),默认值为3。

对于 PPM,PGM,PBM格式的图像,改参数表示一个二进制格式标志(CV_IMWRITE_PXM_BINARY),默认为1。

综合实例代码

#include<opencv2/opencv.hpp>
#include<vector>

using namespace cv;
using namespace std;

void createAlphaMat(Mat mat);

int main()
{
	Mat srcImage = imread("cat.jpg");
	namedWindow("原图");
	imshow("原图", srcImage);

	//创建带有 Alpha 通道的 Mat
	Mat mat(480, 640, CV_8UC4);
	createAlphaMat(mat);

	vector<int> compression_params;
	compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
	compression_params.push_back(9);

	try {
		imwrite("透明 Alpha 值图.png", mat, compression_params);
		imshow("生成的 PNG 图", mat);
		fprintf(stdout, "PNG图片文件的 alpha 数据保存完毕\n 可以在工程目录下查看\n");
		waitKey(0);
	}
	catch (runtime_error& er) {
		fprintf(stderr, "图片转换成PNG格式发生错误:%s\n", er.what());
		return 1;
	}

	return 0;

}

void createAlphaMat(Mat mat)
{
	for(int i = 0; i < mat.rows; i++)
	{ 
		for (int j = 0; j < mat.cols; j++)
		{
			Vec4b& rgba = mat.at<Vec4b>(i, j);
			rgba[0] = UCHAR_MAX;
			rgba[1] = saturate_cast<uchar>((float(mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX);
			rgba[2] = saturate_cast<uchar>((float(mat.rows - i)) / ((float)mat.cols) * UCHAR_MAX);
			rgba[3] = saturate_cast<uchar>(0.5 * (rgba[1] + rgba[2]));
		}
	}
}

运行结果如下图:

滑动条的创建和使用

滑动条(Trackbar)是 OpenCV 动态调节参数特别好用的一种工具,它依附于窗口存在。

1. createTrackbar() 函数。原型如下:

int createTrackbar(const string& trackbarname, const string& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata = 0);

(1)第一个参数,const string& 类型的 trackbarname,为要创建的轨迹条的名字。

(2)第二个参数,const string& 类型的 winname,为窗口的名字。轨迹条依附于该窗口。

(3)第三个参数,int* 类型的 value,为一个指向整形的指针,表示创建滑块时的初始值。

(4)第四个参数,int 类型的 count,表示滑块可以达到的最大位置的值。最小位置值始终为0。

(5)第五个参数,TrackbarCallback 类型的 onChange,默认值为0。为一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调。并且这个函数的原型必须为 void XXX(int, void*),其中第一个参数是轨迹条的位置,第二个参数是用户数据(看下面的第六个参数)。如果回调是 NULL 指针,则表示没有回调函数的调用,仅第三个参数 value 有变化。

(6)第六个参数,void* 类型的userdata,也有默认值0。这个参数是用户传给回调函数的数据,用来处理轨迹条事件。如果使用的第三个参数 value 实参是全局变量的话,完全可以不去管该参数。

实例代码如下:

#include<opencv2/opencv.hpp>

using namespace cv;

#define WINDOW_NAME "【线性混合实例】"

const int g_nMaxAlphaValue = 100;//Alpha 值的最大值
int g_nAlphaValueSlider = 30;//滑动条初始值
double g_dAlphaValue;
double g_dBetaValue;

//声明存储图像的变量

Mat g_srcImage1, g_srcImage2, g_dstImage;

void on_Trackbar(int, void*);

int main()
{
	g_srcImage1 = imread("WindowsLogo.jpg");
	g_srcImage2 = imread("LinuxLogo.jpg");

	namedWindow(WINDOW_NAME);

	char trackbarName[50];
	sprintf_s(trackbarName, "透明值 %d", g_nMaxAlphaValue);

	createTrackbar(trackbarName, WINDOW_NAME, &g_nAlphaValueSlider, g_nMaxAlphaValue, on_Trackbar);

	on_Trackbar(g_nAlphaValueSlider, 0);

	waitKey(0);
	return 0;
}

void on_Trackbar(int, void*)
{
	g_dAlphaValue = (double)g_nAlphaValueSlider / g_nMaxAlphaValue;
	g_dBetaValue = 1.0 - g_dAlphaValue;

	addWeighted(g_srcImage1, g_dAlphaValue, g_srcImage2, g_dBetaValue, 0.0, g_dstImage);

	imshow(WINDOW_NAME, g_dstImage);
}

运行结果如下:

addWeighted() 函数用于两幅图像的线性混合。原型如下:

void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype = -1);

(1)第一个参数,InputArray 类型的 src1,为输入的第一幅图像。

(2)第二个参数,double 类型的 alpha,为混合时第一幅图像元素所占的比重。

(3)第三个参数,InputArray 类型的 src2,为输入的第二幅图像。

(4)第四个参数,double 类型的 beta,为混合时第二幅图像元素所占的比重。

(5)第五个参数,double 类型的 gamma,加到权重总和上的权重。

(6)第六个参数,OutputArray 类型的 dst,为混合后的输出图像。

(7)第七个参数,int 类型的 dtype,输出阵列的可选深度,默认为 -1。当两幅图像的深度相同时,参数设置为 -1,即混合后的图像深度与混合前的图像深度一样。

2.getTrackbarPos()  函数。原型如下:

int getTrackbarPos(const string& trackbarname, const string& winname);

(1)第一个参数,const string& 类型的 trackbarname,为轨迹条的名字。

(2)第二个参数,const string& 类型的 winname,为轨迹条依附的窗口的名字。

鼠标操作

鼠标操作和滑动条的消息映射方式类似,都是通过回调函数实现的。

1. setMouseCallback() 函数。原型如下:

void setMouseCallback(const string& winname, MouseCallback onMouse, void* userdata = 0);

(1)第一个参数,const string&类型的 winname,窗口的名字。

(2)第二个参数,MouseCallback 类型的 onMouse 函数,为每次鼠标事件发生时的回调函数。其原型为 void Foo(int event, int x, int y, int flags, void* param)。event 是 EVENT_+ 变量之一,x 和 y 是鼠标指针在图像坐标系中的坐标值(区别窗口坐标系),flags 是 EVENT_FLAG 的组合,param 是用户定义的传递到 setMouseCallback 函数的参数。如 EVENT_MOUSEMOVE 为鼠标移动消息,EVENT_LBUTTONDOWN 为鼠标左键按下消息等。

(3)第三个参数,void* 类型的 userdata,用户定义的传递到回调函数的参数,默认值为0。参考createTrackbar 函数。

实例代码如下:

#include<opencv2/opencv.hpp>

using namespace cv;

#define WINDOW_NAME "【窗口程序】"

void on_MouseHandle(int event, int x, int y, int flags, void* param);
void drawRectangle(Mat& img, Rect box);

Rect g_rectangle;
bool g_bDrawingBox = false; //是否进行绘制
RNG g_rng(12345);

int main()
{
	//准备参数
	g_rectangle = Rect(-1, -1, 0, 0);
	Mat srcImage(600, 800, CV_8UC3), tempImage;
	srcImage.copyTo(tempImage);
	srcImage = Scalar::all(0);

	//设置鼠标操作回调函数
	namedWindow(WINDOW_NAME);
	setMouseCallback(WINDOW_NAME, on_MouseHandle, (void*)& srcImage);

	//程序主循环,当进行绘制的标识符为真时,进行绘制
	while (1)
	{
		srcImage.copyTo(tempImage);
		if (g_bDrawingBox)
			drawRectangle(tempImage, g_rectangle);
		imshow(WINDOW_NAME, tempImage);
		//按下 ESC 键,退出程序
		if (waitKey(10) == 27)
			break;
	}

	return 0;

}

void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
	Mat& image = *(Mat*)param;
	switch (event)
	{
	//鼠标移动消息
	case EVENT_MOUSEMOVE:
	{
		//如果绘制标识符为真,则记录下长和宽到 RECT 型变量中
		if (g_bDrawingBox)
		{
			g_rectangle.width = x - g_rectangle.x;
			g_rectangle.height = y - g_rectangle.y;
		}
		break;

	//左键按下消息
	case EVENT_LBUTTONDOWN:
	{
		g_bDrawingBox = true; //绘制符置为 true
		g_rectangle = Rect(x, y, 0, 0); //记录起始点
	}

		break;

	//左键抬起消息
	case EVENT_LBUTTONUP:
	{
		g_bDrawingBox = false; //绘制符置为 false
		if (g_rectangle.width < 0)
		{
			g_rectangle.x += g_rectangle.width;
			g_rectangle.width *= -1;
		}
		if (g_rectangle.height < 0)
		{
			g_rectangle.y += g_rectangle.height;
			g_rectangle.height *= -1;
		}

		//调用函数进行绘制
		drawRectangle(image, g_rectangle);

		break;

	}

	}
	default:
		break;
	}
}

//矩形绘制函数
void drawRectangle(Mat& img, Rect box)
{
	//随机给定绘制颜色
	rectangle(img, box.tl(), box.br(), Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255)));

}

RNG 函数官方文档 

Rect 类的成员变量有 x、y、width、height,分别为左上角点的坐标和矩形的宽和高。常用的成员函数有:Size() 返回 Size;area() 返回矩形的面积;contains(Point) 判断点是否在矩形内;inside(Rect) 判断矩形是否在该矩形内;tl() 返回左上角点坐标;br() 返回右下角点坐标。

猜你喜欢

转载自blog.csdn.net/dashujua/article/details/82260651
今日推荐