OpenCV C++学习笔记

1.图像的读取与显示

1.1 加载并显示一张图片

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace cv;
using namespace std;
int main(int argc,char** argv){
    Mat src=imread("sonar.jpg");//读取图像
    if(src.empty()){
        printf("Could not open or find the image\n");
        return -1;
    }
    namedWindow("test opencv setup",CV_WINDOW_AUTOSIZE);
    imshow("test opencv setup",src);//显示图像,窗口命名为test opencv setup

    waitKey(0);//显示按键,0表示无限等待
    return 0;
}

1.2 窗口大小自由调整

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace cv;
using namespace std;
int main(int argc,char** argv){
    Mat src=imread("sonar.jpg");//读取图像
    if(src.empty()){
        printf("Could not open or find the image\n");
        return -1;
    }
    namedWindow("test opencv setup",WINDOW_FREERATIO);//创建一个窗口,窗口名为“test opencv setup“,窗口属性为自由比例
    imshow("test opencv setup",src);//显示图像

    waitKey(0);//显示按键,0表示无限等待
    destroyAllWindows();
    return 0;
}

1.3 图像的读取方式

IMREAD_UNCHANGED:读取原图像,包括alpha通道
IMREAD_GRAYSCALE:以灰度图像读取
IMREAD_COLOR:以彩色图像读取
IMREAD_ANYDEPTH:以原图像深度读取
IMREAD_ANYCOLOR:以原图像颜色格式读取
IMREAD_LOAD_GDAL:使用GDAL读取图像
IMREAD_REDUCED_GRAYSCALE_2:以1/2的灰度图像读取
IMREAD_REDUCED_COLOR_2:以1/2的彩色图像读取
IMREAD_REDUCED_GRAYSCALE_4:以1/4的灰度图像读取

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace cv;
using namespace std;
int main(int argc,char** argv){
    Mat src=imread("sonar.jpg",IMREAD_GRAYSCALE);//读取图像
    if(src.empty()){
        printf("Could not open or find the image\n");
        return -1;
    }
    namedWindow("test opencv setup",WINDOW_AUTOSIZE);//创建一个窗口,窗口名为“test opencv setup“,窗口属性为自由比例
    imshow("test opencv setup",src);//显示图像

    waitKey(0);//显示按键,0表示无限等待
    destroyAllWindows();
    return 0;
}

1.4 图像色彩空间转换

Testdemo.cpp

#include"Testdemo.h"

TestDemo::TestDemo()
{}
TestDemo::~TestDemo()
{}

void TestDemo::colorSpace_demo(Mat& image)
{
    cv::Mat gray,hsv,ycrcb;

    //创建三个窗口,窗口名分别为 “Gray” “HSV” “YCrCb”,窗口属性为自由比例
    namedWindow("Gray",WINDOW_FREERATIO);
    namedWindow("HSV",WINDOW_FREERATIO);
    namedWindow("YCrCb",WINDOW_FREERATIO);

    //转换图像颜色空间
    cvtColor(image,gray,COLOR_BGR2GRAY);//将图像转换为灰度图
    cvtColor(image,hsv,COLOR_BGR2HSV);//将图像转化为HSV图像
    cvtColor(image,ycrcb,COLOR_BGR2YCrCb);//将图像转化为YCrCb图像

    //显示图像
    imshow("Gray",gray);
    imshow("HSV",hsv);
    imshow("YCrCb",ycrcb);

    //保存转换后的图像
    imwrite("/home/liutao/Desktop/222/gray.png",gray);
    imwrite("/home/liutao/Desktop/222/hsv.png",hsv);
    imwrite("/home/liutao/Desktop/222/ycrcb.png",ycrcb);
}

Testdemo.h

#pragma once
#include<opencv2/opencv.hpp>

using namespace cv;

class TestDemo
{
    public:
        TestDemo();
        ~TestDemo();
        void colorSpace_demo(Mat& image); //颜色空间转换、传入图像
};

main.cpp

#include<iostream>
#include<opencv2/opencv.hpp>
#include"Testdemo.h"
#include"test.h"
using namespace std;


int main(int argc,char** argv){

    Mat img =imread("/home/liutao/Desktop/222/sonar.jpg");
    if(img.empty())
    {
        cout<<"could not open or find the image"<<endl;
        return -1;
    }
    namedWindow("Image",WINDOW_AUTOSIZE);
    imshow("Image",img);

    TestDemo testdemo;
    testdemo.colorSpace_demo(img);


    waitKey(0);
    destroyAllWindows();


    
    return 0;

}

在这里插入图片描述

1.5 inrange

Scalar(B,G.R,C) Blue,Green,Red,Channels
Scalar(H,S.V) hue色调,saturation饱和度,value亮度
Scalar lower = Scalar(hmin, smin, vmin); // 效果等同于 Scalar lower = { hmin, smin, vmin}
Scalar upper = Scalar(hmax, smax,vmax);
inRange(imgHSV, lower, upper, mask);

void TestDemo::inrange_colorSpace_demo(Mat& image)
{
	cv::Mat hsv;
	cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);		// 将图像转换为 HSV 图
	namedWindow("hsv", WINDOW_FREERATIO);
	imshow("hsv", hsv);
 
	cv::Mat mask;
	//提取偏红色区域
	inRange(hsv, cv::Scalar(0, 43, 46), cv::Scalar(10, 255, 255), mask);
	// 提取指定色彩范围的区域,参数为输入图像、颜色下限、颜色上限、输出图像
 
 
	cv::namedWindow("mask", cv::WINDOW_FREERATIO);
	cv::imshow("mask", mask);
}

在这里插入图片描述

1.6 数据访问

void TestDemo::mat_demo()
{
	Mat m1 = Mat::zeros(3, 3, CV_8UC3);		// 创建一个 3x3 的 3 通道图像,像素值为 0
	//输出行数、列数、通道数
	std::cout << "m1:\n" << m1 << std::endl;
	std::cout << "m1.rows: " << m1.rows << std::endl;
	std::cout << "m1.cols: " << m1.cols << std::endl;
	std::cout << "m1.channels: " << m1.channels() << std::endl;
 
}

在这里插入图片描述

用Mat创建一个底色为白色图像,通道为RGB

	//通过scalar创建一个 255x255 的 3 通道图像,像素值为 255
	Mat m3 = Mat(255, 255, CV_8UC3, Scalar(255, 255, 255));
	std::cout << "m3:\n" << m3 << std::endl;
	imshow("m3", m3);
	cv::waitKey(0);
	cv::destroyAllWindows();

在这里插入图片描述

1.7图像像素访问

void TestDemo::pixel_read_write(Mat& image)
{
	int width = image.cols;		// 获取图像宽度
	int height = image.rows;	// 获取图像高度
	int channels = image.channels();	// 获取图像通道数
 
	//for (int row = 0; row < height; row++)
	//{
	//	for (int col = 0; col < width; col++)
	//	{
	//		if (channels == 1)	//单通道,图像为灰度
	//		{
	//			int pv = image.at<uchar>(row, col);	// 获取像素值,at<uchar>表示获取灰度图像的像素值,取值范围为0-255
	//			image.at<uchar>(row, col) = 255 - pv;	// 修改像素值,取反
	//		}
	//		if (channels == 3) //三通道图像,彩色图像
	//		{
	//			Vec3b pv_bgr = image.at<Vec3b>(row, col);	// 获取像素值,at<Vec3b>表示获取彩色图像的像素值,bgr通道
	//			image.at<Vec3b>(row, col)[0] = 255 - pv_bgr[0];	// 修改像素值,取反,Vec3b[0]表示B通道
	//			image.at<Vec3b>(row, col)[1] = 255 - pv_bgr[1];	// 修改像素值,取反,G通道
	//			image.at<Vec3b>(row, col)[2] = 255 - pv_bgr[2];	// 修改像素值,取反,R通道
	//		}
 
	//	}
	//}
 
	//通过指针访问像素
	//指针访问像素
	for (int row = 0; row < height; row++)
	{
		uchar* data = image.ptr<uchar>(row);	// 获取图像第 row 行的指针
		for (int col = 0; col < width; col++)
		{
			if (channels == 1)	//单通道,图像为灰度
			{
				*data++ = 255 - *data;	// 修改像素值,取反
			}
			if (channels == 3) //三通道图像,彩色图像
			{
				*data++ = 255 - *data;	// 修改像素值,取反,B通道
				*data++ = 255 - *data;	// 修改像素值,取反,G通道
				*data++ = 255 - *data;	// 修改像素值,取反,R通道
			}
		}
	}
 
 
	namedWindow("pixel_read_write", WINDOW_FREERATIO);
	imshow("pixel_read_write", image);
 
 
}

在这里插入图片描述

1.8 图像的算数操作

void TestDemo::arithmetic_demo(Mat& image)
{
	Mat m1;
	Mat m2;
	m1 = image - Scalar(100, 100, 100);	// 图像减法
	m2 = image + Scalar(100, 100, 100);	// 图像加法
 
	namedWindow("arithmetic_demo_m1", WINDOW_FREERATIO);
	imshow("arithmetic_demo_m1", m1);
	namedWindow("arithmetic_demo_m2", WINDOW_FREERATIO);
	imshow("arithmetic_demo_m2", m2);
}

在这里插入图片描述
当进行像素值操作后,有些值超过了255(对于8位图像,像素值的范围是0到255)时,可以选择进行饱和操作(saturate),将超过范围的值强制截断到合法范围内。OpenCV 中的 cv::saturate_cast 函数可以完成这个任务

 img=img * 2;//进行一些操作,可能导致像素值超过255
    //将图像像素值饱和到0到255的范围
    int height=img.rows;
    int width =img.cols;
    int channels=img.channels();
    for(int row=0;row<height;row++){
        uchar* data = img.ptr<uchar>(row);
        for(int col = 0;col<width;col++){
            *data++=saturate_cast<uchar>(*data);
        }
    }
        
    namedWindow("SATURATE_CAST",WINDOW_FREERATIO);
    imshow("SATURATE_CAST",img);

在这里插入图片描述

1.9 图像像素逻辑操作

void TestDemo::bitwise_demo(Mat& image1, Mat& image2)
{
	Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
	Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
 	// image1 image2
	//创建矩形
	//线宽-1表示填充,线宽>0表示边框宽度
	rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);
	// 矩形填充,颜色为黄色,线宽为-1,表示填充,线型为8连通,矩形左上角坐标为(100,100),宽高为80
 
	rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
	// 矩形填充,颜色为青色,线宽为-1,表示填充,线型为8连通,矩形左上角坐标为(150,150),宽高为80
 
	imshow("m1", m1);
	imshow("m2", m2);
 
	Mat dst_and, dst_or, dst_not, dst_xor;
	bitwise_and(m1, m2, dst_and);	// 与操作
	bitwise_or(m1, m2, dst_or);		// 或操作
	bitwise_not(m1, dst_not);		// 非操作
	bitwise_xor(m1, m2, dst_xor);	// 异或操作
 
	imshow("dst_and", dst_and);
	imshow("dst_or", dst_or);
	imshow("dst_not", dst_not);
	imshow("dst_xor", dst_xor)}

在这里插入图片描述

1.10通道分离与合

void TestDemo::channel_demo(Mat& image)
{
	Mat bgr[3];
	split(image, bgr);	// 通道分离
	namedWindow("B", WINDOW_FREERATIO);
	namedWindow("G", WINDOW_FREERATIO);
	namedWindow("R", WINDOW_FREERATIO);
	imshow("B", bgr[0]);
	imshow("G", bgr[1]);
	imshow("R", bgr[2]);
 
	Mat dst;
	bgr[1] = 0;			// 将 G 通道置为 0
	bgr[2] = 0;			// 将 R 通道置为 0
	merge(bgr, 3, dst);	// 通道合并
	namedWindow("channel_demo", WINDOW_FREERATIO);
	imshow("channel_demo", dst);
}

在这里插入图片描述

1.11 混合图像

	//混合图像
	Mat src1 = image;
	Mat src2 = dst;
	Mat dst2;
	addWeighted(src1, 0.5, src2, 0.5, 0, dst2);	// 图像混合
	namedWindow("channel_demo2", WINDOW_FREERATIO);
	imshow("channel_demo2", dst2);

在这里插入图片描述

1.12 像素值统计

void TestDemo::pixel_statistics(Mat& image){
    double minVal,maxVal;
    Point minLoc,maxLoc;
    vector<Mat>mv;
    split(image,mv);//通道分离
    for(int i=0;i<mv.size();i++)
    {
        minMaxLoc(mv[i],&minVal,&maxVal,&minLoc,&maxLoc);
        //src:输入数组或者向量,必须包含至少一个元素。
        // minVal:可选的输出参数,用于存储最小值的实际值。如果不需要这个值,可以设为0。
        // maxVal:可选的输出参数,用于存储最大值的实际值。如果不需要这个值,可以设为0。
        // minLoc:可选的输出参数,用于存储最小值的位置。如果不需要这个值,可以设为0。
        // maxLoc:可选的输出参数,用于存储最大值的位置。如果不需要这个值,可以设为0。
        // mask:可选的掩码,其大小和类型必须与 src 相同。如果指定了此参数,那么函数只查找具有非零掩码值的元素。
        cout<<"channel "<<i<<"  minVal:"<<minVal<<" maxVal:"<<maxVal<<endl;
    }
    Mat mean,stddev;
    meanStdDev(image,mean,stddev);
    cout<<"mean:"<<mean<<endl<<"stddev:"<<stddev<<endl;

}

在这里插入图片描述

1.13 几何形状绘制

 
void TestDemo::draw_demo()
{
	//创建一个白色底板的图像
	Mat image = Mat::zeros(Size(512, 512), CV_8UC3);
	image = Scalar(255, 255, 255);
 
	//绘制直线
	line(image, Point(100, 100), Point(200, 200), Scalar(0, 0, 255), 2, LINE_8, 0);
	// 直线绘制,颜色为红色,线宽为2,线型为8连通,起点坐标为(100,100),终点坐标为(200,200)
 
	//绘制矩形
	rectangle(image, Rect(200, 200, 100, 100), Scalar(0, 255, 0), 2, LINE_8, 0);
	// 矩形绘制,颜色为绿色,线宽为2,线型为8连通,矩形左上角坐标为(200,200),宽高为100
 
	//绘制圆形
	circle(image, Point(300, 300), 50, Scalar(255, 0, 0), 2, LINE_8, 0);
	// 圆形绘制,颜色为蓝色,线宽为2,线型为8连通,圆心坐标为(300,300),半径为50
 
	//绘制椭圆
	ellipse(image, Point(400, 400), Size(100, 50), 0, 0, 360, Scalar(255, 255, 0), 2, LINE_8, 0);
	// 椭圆绘制,颜色为黄色,线宽为2,线型为8连通,椭圆中心坐标为(400,400),长轴宽度为100,短轴宽度为50
 
	//绘制多边形
	std::vector<Point> points;
	points.push_back(Point(100, 400));
	points.push_back(Point(200, 300));
	points.push_back(Point(300, 400));
	points.push_back(Point(400, 300));
	points.push_back(Point(500, 400));
	const Point* ppt[1] = { points.data() };
	int npt[] = { points.size() };
	fillPoly(image, ppt, npt, 1, Scalar(0, 255, 255), LINE_8, 0);
 
	//显示图像
	namedWindow("draw_demo", WINDOW_FREERATIO);
	imshow("draw_demo", image);
}

在这里插入图片描述

void TestDemo::draw_demo(Mat& image)
{
    //在图像的人脸上绘制矩形
    Mat img =image.clone();
    rectangle(img,Rect(380,400,700,700),Scalar(0,255,0),3,0,0);

    //显示图像
    namedWindow("draw_demo",WINDOW_FREERATIO);
    imshow("draw_demo",img);

    //保存图像
    imwrite("draw_demo.jpg",img);
}

在这里插入图片描述

1.14 随机数与随机颜色

 
void TestDemo::draw_demo_random_color(Mat& image)
{//创建一个白色底板的图像
	Mat img = Mat::zeros(Size(512, 512), CV_8UC3);
	img = Scalar(255, 255, 255);
 
	//绘制随机颜色的直线
	RNG rng(12345);
	for (int i = 0; i < 100; i++)
	{
		Point pt1, pt2;
		pt1.x = rng.uniform(0, 512);
		pt1.y = rng.uniform(0, 512);
		pt2.x = rng.uniform(0, 512);
		pt2.y = rng.uniform(0, 512);
		line(img, pt1, pt2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 2, LINE_8, 0);
	}
 
	//显示图像
	namedWindow("draw_demo_random_color", WINDOW_FREERATIO);
	imshow("draw_demo_random_color", img);
 
	//保存图像
	imwrite(image_path + "/draw_demo_random_color.jpg", img);
}

在这里插入图片描述

1.15 多边形填充与绘制

 
void TestDemo::draw_polyline()
{
	//创建一个白色底板的图像
	Mat img = Mat::zeros(Size(512, 512), CV_8UC3);
	img = Scalar(255, 255, 255);
 
	//绘制多边形
	std::vector<Point> points;
	points.push_back(Point(100, 400));
	points.push_back(Point(200, 300));
	points.push_back(Point(300, 400));
	points.push_back(Point(400, 300));
	points.push_back(Point(500, 400));
	const Point* ppt[1] = { points.data() };
	int npt[] = { points.size() };
	polylines(img, ppt, npt, 1, true, Scalar(0, 255, 255), 2, LINE_8, 0);
 
	//显示图像
	namedWindow("draw_polyline", WINDOW_FREERATIO);
	imshow("draw_polyline", img);
 
}

在这里插入图片描述

1.16 鼠标操作与响应

void  on_mouse(int event,int x,int y,int flags,void* data)
{
    Mat image= *(Mat*)data;
    cout<<"x: "<<x<<"y: "<<y<<endl;
    if(event == EVENT_LBUTTONDBLCLK)
    {
        cout<<"Letf button of the mouse is clicked - position ("<<x<<","<<y<<")"<<endl;
    }
    if(event == EVENT_RBUTTONDBLCLK)
    {
        cout<<"Right button of the mouse is clicked - position("<<x<<","<<y<<")"<<endl;
    }

}

void TestDemo::mouse_demo(Mat& image)
{
    //检测鼠标所在的位置,在图像右下角显示鼠标所在的位置,以及像素值
    namedWindow("mouse_demo",WINDOW_FREERATIO);
    imshow("mouse_demo",image);
    
    setMouseCallback("mouse_demo",on_mouse,(void*)(&image));
}

鼠标事件函数原型:setMouseCallback(),此函数会在调用之后不断查询回调函数onMouse(),直到窗口销毁

  void setMouseCallback(
	const String& winname, 
	MouseCallback onMouse, 
	void* userdata = 0
)

参数解释:
 winname:窗口名称;
 onMouse:回调函数;
 userdata:传递给回调函数用户自定义的外部数据,userdata是一个 void 类型的指针;


回调函数onMouse(),可随意命名,但是要与 setMouseCallback()函数里的回调函数名称一致

void onMouse(
	int event, 
	int x, 
	int y, 
	int flags, 
	void *userdata
) 

参数解释:
event:表示鼠标事件类型的常量(
	#define CV_EVENT_MOUSEMOVE 0             //滑动
	#define CV_EVENT_LBUTTONDOWN 1           //左键点击
	#define CV_EVENT_RBUTTONDOWN 2           //右键点击
	#define CV_EVENT_MBUTTONDOWN 3           //中键点击
	#define CV_EVENT_LBUTTONUP 4             //左键放开
	#define CV_EVENT_RBUTTONUP 5             //右键放开
	#define CV_EVENT_MBUTTONUP 6             //中键放开
	#define CV_EVENT_LBUTTONDBLCLK 7         //左键双击
	#define CV_EVENT_RBUTTONDBLCLK 8         //右键双击
	#define CV_EVENT_MBUTTONDBLCLK 9         //中键双击
);
x和y:鼠标指针在图像坐标系的坐标;
flags:鼠标事件标志的常量;
userdata:回调函数接收,用户自定义的外部数据,userdata是一个 void 类型的指针;


1.7 图像像素类型转化与归一化

void TestDemo:: pixel_type_conversion(Mat& image)
{
    namedWindow("pixel_type_conversion",WINDOW_FREERATIO);
    namedWindow("pixel_type_conversion_normalize",WINDOW_FREERATIO);
    //图像像素类型转化与归一化
    Mat gray;
    cvtColor(image,gray,COLOR_BGR2GRAY);//将图像转换为灰度图
    imshow("pixel_type_conversion",gray);

    //像素归一化
    Mat dst;
    normalize(gray,dst,0,255,NORM_MINMAX,CV_8UC1);
    imshow("pixel_type_conversion_normalize",dst);

}

在这里插入图片描述

1.8 图像缩放与插值

void TestDemo::resize_demo(Mat& image,int x,int y)
{
    Mat dst;
    //图像缩放,参数为输入图像、输出图像、目标图像大小、x方向缩放因子、y方向缩放因子、插值方式
    resize(image,dst,Size(x,y),0,0,INTER_LINEAR);
    imshow("resize_demo",dst);
}

C++ OpenCV中的resize函数用于调整图像的大小。它可以根据指定的尺寸和插值方法对图像进行缩放。函数原型如下:
void cv::resize(InputArray src, OutputArray dst, Size size, double fx = 0, double fy = 0, int interpolation = INTER_LINEAR);
参数说明:

src:输入图像,通常为cv::Mat类型。
dst:输出图像,与输入图像具有相同的类型。
size:目标图像的尺寸,表示为(width, height)。
fx:沿水平轴的缩放因子,默认为0,表示不进行水平缩放。
fy:沿垂直轴的缩放因子,默认为0,表示不进行垂直缩放。
interpolation:插值方法,有以下几种可选:
    cv::INTER_NEAREST:最近邻插值,速度最快,但质量最差。
    cv::INTER_LINEAR:线性插值,速度较快,质量较好。
    cv::INTER_AREA:区域插值,适用于图像缩小,速度较慢,质量最好。
    cv::INTER_CUBIC:三次样条插值,速度适中,质量较好。
    cv::INTER_LANCZOS4:Lanczos插值,速度适中,质量较好。

在这里插入图片描述

1.9 图像翻转

void TestDemo::flip_demo(Mat& image,int flipCode)
{
    Mat dst;
    //图像翻转,参数为输入图像、输出图像、翻转方式
    //flipCode=0表示绕x轴翻转,flipCode>0表示绕y轴翻转,flipCOde<0表示绕x轴和y轴同时翻转
    flip(image,dst,flipCode);
    namedWindow("flip_demo",WINDOW_FREERATIO);
    imshow("flip_demo",dst);
}

在这里插入图片描述

1.20 图像旋转

warpAffine函数介绍
warpAffine函数是OpenCV中的一个函数,用于对图像进行仿射变换,包括旋转、缩放、平移等操作。该函数可以对图像进行二维或三维的仿射变换,支持多种插值方法和输出图像格式。

warpAffine是OpenCV中的一个函数,用于对图像进行仿射变换,包括旋转、缩放、平移等操作。该函数可以对图像进行二维或三维的仿射变换,支持多种插值方法和输出图像格式。

void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())

Parameters:

src – Source image.
dst – Destination image that has the size dsize and the same type as src .
M – 2\times 3 transformation matrix.
dsize – Size of the destination image.
flags – Combination of interpolation methods (see resize() ) and the optional flag WARP_INVERSE_MAP that means that M is the inverse transformation ( \texttt{dst}\rightarrow\texttt{src} ).
borderMode – Pixel extrapolation method (see borderInterpolate() ). When borderMode=BORDER_TRANSPARENT , it means that the pixels in the destination image corresponding to the “outliers” in the source image are not modified by the function.
borderValue – Value used in case of a constant border. By default, it is 0.

The function warpPerspective transforms the source image using the specified matrix:
在这里插入图片描述

getRotationMatrix2D函数介绍

 Mat getRotationMatrix2D(Point2f center, double angle, double scale)

Parameters:

center – Center of the rotation in the source image.
angle – Rotation angle in degrees. Positive values mean counter-clockwise rotation (the coordinate origin is assumed to be the top-left corner).
scale – Isotropic scale factor.
mapMatrix – The output affine transformation, 2x3 floating-point matrix.

The function calculates the following matrix:
在这里插入图片描述
where
在这里插入图片描述

void TestDemo::rotate_demo(Mat& image,double angle,double scale)
{
    /*
    参数angle表示旋转角度,正值表示逆时针旋转,负值表示顺时针旋转
    参数scale表示缩放因子,大于1表示放大,小于1表示缩小
    */
   Mat dst,M;
   int w = image.cols;
   int h = image.rows;

   M = getRotationMatrix2D(Point(w/2,h/2),angle,scale);//获取旋转矩阵

   double cos=abs(M.at<double>(0,0));
   double sin=abs(M.at<double>(0,1));

   int nw = cos * w + sin * h;
   int nh = sin * w + cos * h;

   M.at<double>(0,2) +=(nw-w)/2;
   M.at<double>(1,2) +=(nh-h)/2;

   warpAffine(image,dst,M,Size(nw,nh));//图像旋转
   namedWindow("rotate_demo",WINDOW_FREERATIO);
   imshow("rotate_demo",dst);



}

在这里插入图片描述

1.21 视频文件/摄像头使用

void TestDemo::video_demo()
{

    VideoCapture capture(0);//打开摄像头
    if(!capture.isOpened())//摄像头打开失败
    {
        cout<<"摄像头打开失败"<<endl;
        return;
      
    }
    Mat frame;
    while(1)
    {
        capture>>frame;//读取摄像头图像
        //翻转摄像头显示
        flip_demo(frame,1);
        imshow("video_demo",frame);//显示摄像头图像
        if(waitKey(30)==27)//按下esc键
        {
            break;
        }
    }
    capture.release();//释放摄像头
    destroyAllWindows();//销毁所有窗口

}

1.22 视频处理与保存

void TestDemo::videowriter_demo()
{
       //保存视频
    VideoWriter writer;
    Mat frame;
    VideoCapture capture(0);
    Size size=Size(capture.get(CAP_PROP_FRAME_WIDTH),capture.get(CAP_PROP_FRAME_HEIGHT));
    writer.open("./video_demo.avi",VideoWriter::fourcc('M','J','p','G'),25,size);//fps 25 每秒帧数
    while(1)
    {
        capture>>frame;//读取摄像头图像
        writer.write(frame);//写入视频

        imshow("videowrite_demo",frame);//显示摄像头图像
        if(waitKey(30)==27)//按下ESC键
        {
            break;

        }

    }
    writer.release();//释放视频
    capture.release();
    destroyAllWindows();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/541222.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

吴恩达深度学习 (week3,4)

文章目录 一、神经网络概述二、神经网络的表示三、神经网络的输出四、多个例子的向量化五、向量化实现的解释六、深度学习激活函数七、激活函数导数八、神经网络的梯度下降法九、深度学习随机初始化十、上述学习总结1、第一题2、第二题3、第三题4、第四题5、第五题6、第六题7、…

磁悬浮鼓风机市场规模不断增长 我国行业发展面临挑战

磁悬浮鼓风机市场规模不断增长 我国行业发展面临挑战 磁悬浮鼓风机又称磁悬浮高速离心鼓风机&#xff0c;指基于磁悬浮技术制成的气体输送设备。磁悬浮鼓风机综合性能优良&#xff0c;属于高效节能磁悬浮动力装备&#xff0c;在众多领域需求旺盛。未来随着国家节能环保政策逐渐…

将Visio绘图导出PDF文件,使其自适应大小,并去掉导入Latex的边框显示

问题描述 将Visio绘图导成pdf文件&#xff0c;首先在Visio绘图如下&#xff1a; 如果直接导出或者另存为pdf文件&#xff0c;则会发现pdf文件是整个页面大小&#xff0c;而不是图片大小。而且在导入latex等排版工具现实时&#xff0c;会显示边框。 问题解决 1.调整Visio中的页…

科软24炸穿了,25还能冲吗?

25考研&#xff0c;科软必然保持大热 不是吧兄弟&#xff0c;明眼人都能看出来&#xff0c;科软以后不会出现大冷的局面了&#xff0c;除非考计算机的人减少&#xff0c;因为科软简直是叠满了buff&#xff0c;首先科软的专业课是22408&#xff0c;考的是数学二&#xff0c;这就…

ssm048电子竞技管理平台的设计与实现+jsp

电子竞技管理平台设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本电子竞技管理平台就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短…

jsoncpp 编译和使用

原文链接&#xff1a; jsoncpp的编译和使用 jsoncpp 编译出库文件 1.从github仓库下载 2.下载 cmake 工具 3.生成VS项目 4.编译得到需要的库文件 jsoncpp 的使用 查看原文

JavaEE初阶Day 7:多线程(5)

目录 Day 7&#xff1a;多线程&#xff08;5&#xff09;1. 死锁2. 死锁场景3. 场景二&#xff1a;两个线程&#xff0c;两把锁4. 场景三&#xff1a;N个线程&#xff0c;M把锁5. 避免死锁问题6. 内存可见性问题 Day 7&#xff1a;多线程&#xff08;5&#xff09; 回顾synchr…

【C++】类和对象②(类的默认成员函数:构造函数 | 析构函数)

&#x1f525;个人主页&#xff1a;Forcible Bug Maker &#x1f525;专栏&#xff1a;C 目录 前言 类的6个默认成员函数 构造函数 概念 构造函数的特性及用法 析构函数 概念 析构函数的特性及用法 结语 前言 本篇主要内容&#xff1a;类的6个默认成员函数中的构造函…

ifconfig用法 、默认掩码

文章目录 概述2. ifconfig(尽量别用&#xff0c;已废弃)2.1 配置地址2.1.1 默认掩码 2.2 查看功能2.2.1 ifconfig 查看不含禁用的网卡2.2.2 ifconfig -a 查看含禁用的网卡2.2.3 ip a 2.3 启用、禁用网卡2.3.1 ifconfig eth1 up、 ifconfig eth1 down2.3.2 ifdown eth0、ifip et…

C++string类(个人笔记)

string类 1.认识string的接口以及熟练使用常用接口1.1string类对象的常见构造1.2string类对象的容量操作1.3string类对象的访问及遍历操作1.4string类对象的修改操作 2.vs 和g下string结构的说明3.string类运用的笔试题4.string类的模拟实现 1.认识string的接口以及熟练使用常用…

langchain 文本向量化存储,并检索相似 topK

目录 chroma 检索 faiss 检索 检索器 相似性 最大相关性mmr 相似数阈值 txt 有多行&#xff0c;我的这份数据有 67 行&#xff0c;样例如下&#xff1a; 字段1\t值1\n 字段2\t值2\n ... chroma 检索 pip install langchain-chroma 在本地下载了 embedding 模型&…

使用SquareLine Studio创建LVGL项目到IMX6uLL平台

文章目录 前言一、SquareLine Studio是什么&#xff1f;二、下载安装三、工程配置四、交叉编译 前言 遇到的问题&#xff1a;#error LV_COLOR_DEPTH should be 16bit to match SquareLine Studios settings&#xff0c;解决方法见# 四、交叉编译 一、SquareLine Studio是什么…

单列模式1.0

单列模式 单例模式能保证某个类在程序中只存在唯⼀⼀份实例, ⽽不会创建出多个实例 1.饿汉模式 只要程序一启动就会立即创建出一个对象 class Signleton{private static Signleton instancenew Signleton();//防止在以后的代码中再创建对象&#xff0c;我们将构造方法private,…

LeetCode 24. 两两交换链表中的节点

解题思路 这道题用画图的方法是比较好的。 相关代码 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.…

易语言数据库常用操作

易语言是一门中文编程语言&#xff0c;由国人开发&#xff0c;虽然比较冷门&#xff0c;但是在有些场合却非常流行&#xff0c;比如自动化脚本&#xff0c;还有开发外挂。 本文将介绍在易语言数据库的一些常规操作。 1. 打开数据库 2. 关闭数据库 3. 读取数据库 4. 数据库指针…

英伟达高性能芯片供货周期缩短到2-3个月,今年GPU不再紧缺?

戴尔台湾地区总经理Terence Liao近日称&#xff0c;英伟达高性能 AI GPU的交付周期在过去几个月中已从3-4个月缩短到仅2-3个月&#xff0c;进入2024年以来交货等待时间一直在不短缩短&#xff0c;目前的2-3个月已经是英伟达高性能GPU最短的交货期。 英伟达公司正在不断努力提高…

【Sql Server】锁表如何解锁,模拟会话事务方式锁定一个表然后进行解锁

大家好&#xff0c;我是全栈小5&#xff0c;欢迎来到《小5讲堂》。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言创建表模拟…

云服务器环境web环境搭建之JDK、redis、mysql

一、Linux安装jdk&#xff0c;手动配置环境 链接: https://pan.baidu.com/s/1LRgRC5ih7B9fkc588uEQ1whttps://pan.baidu.com/s/1LRgRC5ih7B9fkc588uEQ1w 提取码: 0413 tar -xvf 压缩包名 修改配置文件/etc/profile 二、安装redis环境 方案一&#xff1a; Linux下安装配置r…

计算机操作系统——2 进程与作业

目录 一、程序&#xff08;一&#xff09;概念&#xff08;二&#xff09;程序的执行 二、进程&#xff08;一&#xff09;概念与特征&#xff08;二&#xff09;进程控制块&#xff08;三&#xff09;进程句柄&#xff08;四&#xff09;进程的状态 三、线程四、作业&#xff…

【STL详解 —— list的介绍及使用】

STL详解 —— list的介绍及使用 list的介绍list的介绍使用list的构造list iterator的使用list capacitylist element accesslist modifiers 示例list的迭代器失效 list的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭…