在OpenCV中生成一个png图片,并写入当前工程目录下
OpenCV的命名空间:using namespace cv;(可不用敲cv::)
Mat类:用于保存图像以及其他矩阵数据的数据结构,默认情况下其尺寸为0;
Mat srcImage=imread("1.jpg");
imread()函数:图像的载入------Mat imread(const string& filename,int flags=1);
参数一:需要载入的图片的路径
参数二:为载入标识,它指定一个加载图像的颜色类型。(flags>0返回3通道彩色图像;=0返回灰度图像;<0返回包含Alpha通道的加载图像)
CV_LOAD_IMAGE_GRAYSCALE------等价取值0(图像转换成灰度图像);
CV_LOAD_IMAGE_COLOR--------等价取值为1(转换图像到彩色再返回);
CV_LOAD_IMAGE_ANYDEPTH-----等价取值为2(深度16,23位返回对应深度图像,否则转换为8位返回)。
imshow()函数:图像的显示-----void imshow(const string& winname,InputArray mat);
参数一:需显示的窗口的名称
参数二:填需要显示的图像
InputArray类型把它简单的看作Mat类型即可。
nameWindow()函数:创建窗口-----void nameWindow(const strin& winname,int flags=WINDOW_AUTOSIZE);
参数一:窗口名称
参数二:窗口的标识(WINDOW_AUTOSIZE窗口大小适应图像大小;WINDOW_NORMAL用户可以改变窗口的大小;WINDOW_OPENGL窗口创建支持OpenGL)
imwrite()函数:输出图像到指定的文件夹
函数原型:bool imwrite(const string& filename,InputArray img,const vector<int>& params=vector<int>());
参数一:需要写入的文件名(带后缀)
参数二:Mat类型的图像数据
参数三:表示为特定格式保存的参数编码(JPEG(0-100)默认值95;PNG(0-9)默认值3;PPM,PGM,PBM(0或1)默认为1)
代码如下:
//------程序一:imwrite函数的用法--在opencv中生成一个PNG图片,并写入到当前工程目录下----
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
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.rows)*UCHAR_MAX);
rgba[3] = saturate_cast<uchar>(0.5*(rgba[1] + rgba[2]));
}
}
}
int main() {
//创建带Alpha通道的Mat
Mat mat(480, 640, CV_8UC4);
createAlphaMat(mat);
vector<int>compression_params;
compression_params.push_back(IMWRITE_PNG_COMPRESSION);
//copression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);OPENCV2版本
compression_params.push_back(9);
try {
imwrite("透明Alpha值图.png", mat, compression_params);
imshow("生成的PNG图", mat);
fprintf(stdout, "PNG图片文件的alpha数据保存完毕\n可以在工程目录下查看由imwrite函数生成的图片\n");
waitKey(0);
}
catch (runtime_error& ex) {
fprintf(stderr, "图像转换成PNG格式发生错误:%s\n", ex.what());
return 1;
}
return 0;
}
程序运行结果:
初级图像混合
代码如下:
//------------程序二:图像的载入、显示与输出(初级图像混合)----------
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int main() {
//-------图像的载入和显示---------
//Mat girl = imread("lenna.jpg");
//namedWindow("lenna图",WINDOW_NORMAL);
//imshow("lenna图",girl);
//--------初级图像混合-----------
Mat image = imread("k.jpg",1);
Mat logo = imread("1.png");
namedWindow("原画图", WINDOW_NORMAL);
imshow("原画图",image);
namedWindow("logo图", WINDOW_NORMAL);
imshow("logo图",logo);
//定义一个Mat类型,用于存放,图像的ROI
Mat imageROI;
//方法一
imageROI = image(Rect(100,150,logo.cols,logo.rows));
//方法二
//imageROI=image(Range(350, 350 + logo.rows), Range(800, 800 + logo.cols));
//将logo加到原图上
addWeighted(imageROI,0.5,logo,0.3,0.0,imageROI);
//显示结果
namedWindow("原图+logo图", WINDOW_NORMAL);
imshow("原图+logo图",image);
//-----------图像的输出----------
imwrite("imwrite生成的图片.jpg",image);
waitKey();
return 0;
}
运行结果:
滑动条的创建和使用
1.滑动条的创建和使用(createTrackbar()函数)
C++函数原型:int createTrackbar(conststring& trackbarname,conststring& winname,int* value,int count,TrackbarCallback onChange=0,void* userdata=0);
参数一:轨迹条的名字
参数二:轨迹条依附的窗口名称
参数三:表示滑块的位置
参数四:表示滑块可以达到的最大位置的值。最小值为0.
参数五:(默认0)这是一个指向回调函数的指针,每次滑块位置改变时,这个函数会进行回调。
参数六:(默认0)用户传给回调函数的数据,用来处理轨迹条事件
2.获取当前轨迹条的位置(getTrackbarPos()函数)
C++函数原型 :int getTrackbarPos(conststring& trackbarname,conststring& winname);
参数一:轨迹条的名字
参数二:轨迹条的父窗口的名称
3.SetMouseCallback()函数为指定的窗口设置鼠标回调函数
C++函数原型:void setMouseCallback(conststring& winname,MouseCallback onMouse,void* userdata=0);
参数一:窗口名字
参数二:窗口里每次鼠标事件发生的时候,被调用的函数指针。
参数三:(默认值0)用户定义的传递到回调函数的参数。
onMouse函数原型:void Foo(int event,int x,int y,int flags,void*param);
参数一:event-----EVENT_MOUSEMOVE:鼠标移动消息;
EVENT_LBUTTONDOWN:鼠标左键按下消息。
参数二:x,y:鼠标指针在图像坐标系中的坐标值(不是窗口坐标系)
参数三:glags:EVENT_FLAG的组合
参数四:param:用户定义的传到SetMouseCallback函数调用的参数
4.sprintf()函数的功能非常强大:效率比一些字符串操作函数要高;而且更具灵活性;可以将想要的结果输出到指定的字符串中,也可作为缓冲区,而printf只能输出到命令行上~
函数功能:格式化字符串,将格式化的数据写入字符串中。
函数原型:int sprintf(char *buffer, const char *format, [argument]...)
参数:(1)buffer:是char类型的指针,指向写入的字符串指针;
(2)format:格式化字符串,即在程序中想要的格式;
(3)argument:可选参数,可以为任意类型的数据;
函数返回值:buffer指向的字符串的长度;
用处:(1)格式化数字字符串:在这点上sprintf和printf的用法一样,只是打印到的位置不同而已,
前者打印给buffer字符串,后者打印给标准输出,所以sprintf也可以用来将整型转化为字符串,
比如:sprintf(buffer, "%d", 123456);执行后buffer即指向字符串“123456”
(2)连接字符
代码如下:
//------------程序三:滑动条的创建和使用(createTrackbar()函数)----------
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
#define WINDOW_NAME "【线性混合示例】"//为窗口标题定义的宏
//------全局变量声明--------
const int g_nMaxAlphaValue = 100;//Alpha值的最大值
int g_nAlphaValueSlider;//滑动条对应的变量
double g_dAlphaValue;
double g_dBetaValue;
//声明存储图像的变量
Mat g_srcImage1;
Mat g_srcImage2;
Mat g_dstImage;
//--------响应滑动条的回调函数-----------
void on_Trackbar(int,void*) {
//求出当前alpha值相对于最大值的比例
g_dAlphaValue = (double)g_nAlphaValueSlider / g_nMaxAlphaValue;
//则beta值为1减去alpha值
g_dBetaValue = (1.0 - g_dAlphaValue);
//根据alpha和beta值进行线性混合
addWeighted(g_srcImage1,g_dAlphaValue,g_srcImage2,g_dAlphaValue,0.0,g_dstImage);
//显示效果图
imshow( WINDOW_NAME , g_dstImage );
}
//--------控制台应用程序的入口函数,我们的程序从这里开始执行-------
int main(int argc,char** argv) {
//加载图像(两图像的尺寸需相同)
g_srcImage1 = imread("lenna.jpg");
g_srcImage2 = imread("lenna.jpg");
if (!g_srcImage1.data) {
printf("读取第一幅图片错误,请确定目录下是否有imread函数指定图片存在! \n");
return -1;
}
if (!g_srcImage2.data) {
printf("读取第一幅图片错误,请确定目录下是否有imread函数指定图片存在! \n");
return -1;
}
//设置滑动条初值为70
g_nAlphaValueSlider = 70;
//创建窗体
namedWindow(WINDOW_NAME,0);
//在创建的窗体中创建一个滑动条控件
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;
}
运行结果:(因运行时需两张相同大小的图片,所以用了两张lenna图)
鼠标交互
代码如下:
//---------程序四:鼠标交互-----------
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
#define WINDOW_NAME "【程序窗口】"//为窗口标题定义的宏
//-------全局函数声明部分--------
void on_MouseHandle(int event,int x,int y,int flags,void* param);
void DrawRectangle(cv::Mat& img,cv::Rect box);
//void ShowHelpText();
//------全局变量声明--------
Rect g_rectangle; //Rect矩阵类
bool g_bDrawingBox = false;
RNG g_rng(12345); //RNG随机类:随机生成
//--------鼠标回调函数on_MouseHandle()函数-----------
void on_MouseHandle(int event, int x, int y, int flags, void* param) {
Mat& image = *(cv::Mat*) param;
switch (event) {
//鼠标移动消息
case EVENT_MOUSEMOVE: {
if (g_bDrawingBox) //如果是否进行绘制的标识符为真,则记录下长和宽到RECT型变量中
{
g_rectangle.width = x-g_rectangle.x;
g_rectangle.height = y-g_rectangle.y;
}
}
break;
//左键按下消息
case EVENT_LBUTTONDOWN: {
g_bDrawingBox = true;
g_rectangle = Rect(x,y,0,0);//记录起始点
}
break;
//左键抬起消息
case EVENT_LBUTTONUP: {
g_bDrawingBox = false;//置标识符为false
//对宽和高小于0的处理
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;
}
}
//--------自定义的矩形绘制函数---------
void DrawRectangle(cv::Mat& img, cv::Rect box) {
rectangle(img,box.tl(),box.br(),Scalar(g_rng.uniform(0,255),g_rng.uniform(0,255),g_rng.uniform(0,255)));//随机颜色
}
//--------控制台应用程序的入口函数-------
int main(int argc, char** argv) {
//准备参数
g_rectangle = Rect(-1,-1,0,0);
Mat srcImage(600, 800, CV_8UC3), tempImage;
srcImage.copyTo(tempImage);
g_rectangle = Rect(-1, -1, 0, 0);
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);
if (waitKey(10) == 27)
break;
}
return 0;
waitKey(0);
return 0;
}
运行结果: