目录
图像的载入与显示
输出图像到文件
综合实例代码
滑动条的创建和使用
鼠标操作
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& params=vector());
(1)第一个参数,const string& 类型的 filename,为将要写入的文件名。注意要带上后缀,如:"dog.jpg"。
(2)第二个参数,InputArray 类型的 img,一般为 Mat 类型的图像数据。
(3)第三个参数,const vector
对于 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
#include
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 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(i, j);
rgba[0] = UCHAR_MAX;
rgba[1] = saturate_cast((float(mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX);
rgba[2] = saturate_cast((float(mat.rows - i)) / ((float)mat.cols) * UCHAR_MAX);
rgba[3] = saturate_cast(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
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
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() 返回右下角点坐标。