OpenCV学习笔记(二)
imwrite函数:输出图像到文件
imwrite(const string& filename,InputArray img,const vector<int>& params=vector<int> () );
第一个参数:文件名,要带后缀
第二个参数:一般是一个Mat类型对象
第三个参数:特定格式保存的参数编码,有默认值vector<int>,一般不用管
实例:利用imwrite和自定义的通道值建立图片
#include <vector>
#include <stdio.h>
#include<opencv2/opencv.hpp>
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);//Vec4b是像素的类型
rgba[0] = UCHAR_MAX;//255
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;
//此句代码的OpenCV2版为:
//compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
//此句代码的OpenCV3版为:
compression_params.push_back(IMWRITE_PNG_COMPRESSION);
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;
}
图像的载入,显示,输出分别对应imread,imshow,imwrite,没什么好说的。
图像的初级混合:
老版本的方法:Mat imageROI = src1(Rect(100, 100, src2.cols, src2.rows));src2.copyTo(imageROI);
新版本的方法:Mat imageROI = src1(Range(100,100+src2.rows),Range(100,100+src2.cols));src2.copyTo(imageROI);
如果imageROI未重赋值,则ROI是规定尺寸下原图像的一部分
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int main(int argc, char** argv[]) {
Mat src1 = imread("E://hashiqi.jpg");
Mat src2 = imread("E://logo.jpg");
Mat imageROI = src1(Rect(100, 100, src2.cols, src2.rows));
//位置信息
/*Mat imageROI = src1(Range(100,100+src2.rows),Range(100,100+src2.cols));*/
imshow("222", imageROI);
src2.copyTo(imageROI);
imshow("111", src1);
waitKey(0);
}
线性混合用到的addWeighted函数:void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype = -1);
第一个参数:要叠加的第一个图像Mat
第二个参数:标识第一个参数叠加的权重
第三个参数:表示第二个叠加的图像,他需要和第一个数组拥有同样的尺寸和通道数
第四个参数:表示第二个叠加图像的权重
第五个参数:输出参数,需要和前两个图像拥有同样的通道数和尺寸
第六个参数:一个加到权重总和上的标量值(填0就好)
第七个参数:输出阵列的深度有默认值-1, 当两张叠加图片深度相同时,参数为-1
对应表达式为:dst = src1[i] * alpha + src2[i] * beta + gamma;//两张图片每个通道对应数值之和。
注意:addWeighted混合的图像必须有相同的size。
Mat imageROI = src1(Rect(100, 100, src2.cols, src2.rows));
addWeighted(imageROI, 0.5, src2, 0.5, 1., imageROI);
imshow("111", imageROI);
TrackBar:滑动条,滚动条
createTrackbar() :
CV_EXPORTS int createTrackbar(const string& trackbarname, const string& winname,
int* value, int count,
TrackbarCallback onChange = 0,
void* userdata = 0);
参数一:trackbarname:滑动条名
参数:winname:滑动条所述的图像窗口名
参数三:value:初始化阈值
参数四:count:滑动控件的刻度范围,即最大值;
参数五:TrackbarCallback是回调函数,默认值0,其定义如下:
typedef void (CV_CDECL *TrackbarCallback)(int pos, void* userdata);
参数六:void*类型的userdata,默认值0,用户给回调函数的数据,value为全局,不用管userdata
回调函数:主函数中的中间函数以回调函数的指针为参数,使用回调函数的功能,再通知主函数。
很抽象,结合测试代码理解
#include <stdio.h>
typedef int(*callback)(int, int);
int add(int a, int b, callback p) {
return (*p)(a, b);
}
int add(int a, int b) {
return a + b;
}
int main(int argc, char* args[]) {
int res = add(4, 2, add);
printf("%d\n", res);
return 0;
}
通过TrackBar修改权值,观察图像线性混合结果:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
#define WINDOW_NAME "【滑动条的创建&线性混合示例】"
Mat src1;
Mat src2;
Mat temp;
const int Max_Alpha = 100;
//最大透明值
int trackBar_value;
//trackBar当前值
double src1_value;
double src2_value;
//图像1,2的透明值变量
void on_Trackbar(int, void* = 0)
{
//求出当前alpha值相对于最大值的比例
src1_value = (double)trackBar_value / Max_Alpha;
//则beta值为1减去alpha值
src2_value = (1.0 - src1_value);
//根据alpha和beta值进行线性混合
addWeighted(src1, src1_value, src2_value, src2_value, 0.0, temp);
//显示效果图
imshow(WINDOW_NAME, temp);
}
int main(int argc, char** argv[]) {
src2 = imread("E://hashiqi.jpg");
src1 = imread("E://hashiqi2.jpg");
trackBar_value = 70;
namedWindow(WINDOW_NAME, 1);
//char TrackbarName[50];
//sprintf(TrackbarName, "透明值 is %d", 100);
createTrackbar("透明度", WINDOW_NAME, &trackBar_value, Max_Alpha, on_Trackbar);
on_Trackbar(trackBar_value);
waitKey(0);
}
sprintf方法能不用尽量别用,error c4996涉及新旧版本安全问题的不同,想想用别的去吧,建议不要用这个
getTrackbarPos(trackbarname,winname);
getTrackbarPos("透明度",WINDOW_NAME)
鼠标操作:setMouseCallback(const string &winname,MouseCallback onMouse,void * userdata=0)
第二个参数 MouseCallback类型的onMouse,指定窗口里每次鼠标事件发生时,被调用的函数指针
函数原型:void Foo(int event,int x,int y,int flags,void *params)
event是EVENT_+变量之一,x,y是鼠标指针在图像坐标系中的坐标值,flags是EVENT_FLAG的组合,param是用户定义的传递到SetMouseCallback函数调用的参数
例如:EVENT_MOUSEMOVE,EVENT_LBUTTONDOWN
下面是通过鼠标事件,回调函数实现黑幕画随机颜色矩阵
#include <opencv2/opencv.hpp>
using namespace cv;
#define WINDOW_NAME "【程序窗口】"
//回调函数声明
void on_mouse(int event, int x, int y, int flags, void* params);
//矩阵绘图函数
void DrawRectangle(cv::Mat& img, cv::Rect box);
Rect rect_angle;
bool isDraw = false;
RNG rng(12345); //构造方法设定一个具体值,表示下面代码每次生成的结果都是一样的
int main(int argc, char** argv) {
system("color 9F");
rect_angle = Rect(-1, -1, 0, 0);
Mat srcImage(600, 800, CV_8UC3), tempImage;
srcImage.copyTo(tempImage);
rect_angle = Rect(-1, -1, 0, 0);
//通道初始化,出事全黑
srcImage = Scalar::all(0);
//设置鼠标操作回调函数
namedWindow(WINDOW_NAME);
setMouseCallback(WINDOW_NAME, on_mouse, (void*)&srcImage);
//程序主循环,当进行绘制的标识符为真时,进行绘制
while (1)
{
srcImage.copyTo(tempImage);//拷贝源图到临时变量
if (isDraw) DrawRectangle(tempImage, rect_angle);//当进行绘制的标识符为真,则进行绘制
imshow(WINDOW_NAME, tempImage);
if (waitKey(10) == 27) break;//按下ESC键,程序退出
}
return 0;
}
void on_mouse(int event, int x, int y, int flags, void* params) {
Mat& image = *(cv::Mat*) params;
switch (event)
{
case EVENT_MOUSEMOVE: {
if (isDraw) {
//根据收手的点,给矩形置长宽
rect_angle.width = x - rect_angle.x;
rect_angle.height = y - rect_angle.y;
}
}
break;
case EVENT_LBUTTONDOWN:{
//跟矩形初始化
isDraw = true;
rect_angle = Rect(x, y, 0, 0);
}
break;
case EVENT_LBUTTONUP: {
isDraw = false;
if (rect_angle.width < 0) {
rect_angle.x += rect_angle.width;
//因为上面是x-width,所以是负的
rect_angle.width *= -1;
}
if (rect_angle.height < 0) {
rect_angle.x += rect_angle.height;
rect_angle.height *= -1;
}
DrawRectangle(image, rect_angle);
}
break;
}
}
void DrawRectangle(cv::Mat& img, cv::Rect box)
{
cv::rectangle(img, box.tl(), box.br(), cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)));//随机颜色
}