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)));//随机颜色
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值