欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenCV学习笔记(二)

程序员文章站 2022-07-13 21:52:01
...

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;
}

OpenCV学习笔记(二)

图像的载入,显示,输出分别对应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);

}

OpenCV学习笔记(二)

线性混合用到的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);

OpenCV学习笔记(二)

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);

}

OpenCV学习笔记(二)OpenCV学习笔记(二)

sprintf方法能不用尽量别用,error c4996涉及新旧版本安全问题的不同,想想用别的去吧,建议不要用这个

getTrackbarPos(trackbarname,winname);

getTrackbarPos("透明度",WINDOW_NAME)

OpenCV学习笔记(二)

鼠标操作: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)));//随机颜色
}

OpenCV学习笔记(二)