算法组考核任务报告
- 学院:计算机科学与技术学院
- 专业班级:计算机科学与技术 2001 班
- 姓名:刘景宇
- 意向组:算法组
自我感觉应该不会像C语言/数据结构实验报告那么正式吧,所以就写我认为重要的内容了
所有代码的源码将会放在最后的附录中,函数声明以及部分重要代码会在任务的报告中出现。
目录
- 任务一
- 任务二
- 任务三
- 任务四
- 任务五
- 任务六
- 任务七
- 附录
任务一
-
C++创建一个名为complex的结构体,结构体成员分别为:
- float型复数的模
- 长度为2的float型数组,存储复数的常数、复数项
struct complex{ float len; //float类型数据,存放模长 float num[2]; //float类型数组,存放实部和虚部 };
-
编写函数,分别实现复数的加法、乘法、共轭操作,并将结果打印到屏幕上。
-
打印的实现(加、乘、共轭操作都要打印)
按照a+bi的形式打印
如果虚部为非负数,则打印一个加号,否则不打印符号(因为负数自带减号)
-
加法的实现
定义一个变量c存放结果,作为返回值
对应项相加,并计算相加后的复数的模
打印结果
complex add(const complex& c1,const complex& c2);
-
乘法的实现
定义一个变量c作为存放计算结果,作为返回值
按照复数相乘的规则计算,对应的实部和虚部
打印结果
complex mut(const complex& c1,const complex& c2);
-
共轭操作的实现
定义一个变量c存放结果,作为返回值
实部直接赋值,虚部赋相反数,模直接赋值
打印结果
complex con(const complex& c1);
形参使用“常引用”要比直接复制一份效果好一点点。
-
-
定义一个复数类,创建构造函数,调用构造函数时完成对两个复数的复制操作。
- private:存放数据,不允许外部读取更改
- public:相关的函数
- Complex(float x,float y)构造函数:接收两个浮点型数据,作为复数的实部和虚部(目前不考虑重载,这里认为用户输入的均为标准复数),有实部和虚部后立即计算模并存储下来。(这里只保留了基本的构造函数,省略了复制构造函数)
- ~Complex()析构函数,写析构函数(尽管函数体为空),一个好的习惯
class Complex{ private: float len; float num[2]; public: Complex(float x,float y); ~Complex(){} void add(const Complex& c);//求和 void mut(const Complex& c);//乘积 void con();//共轭操作 void print(); }; Complex::Complex(float x,float y){ //类外定义构造函数 num[0]=x; num[1]=y; len=sqrt(x*x+y*y);//计算模长 print(); }
-
用类成员函数完成2中对复数的操作
-
打印
功能同结构体部分的print()函数
void Complex::print();
-
相加
调用对象的add()函数时,传入一个复数对象,将结果保存在调用对象的数据中,并更改模长数据
void Complex::add(const Complex& c);
-
相乘
调用对象的mul()函数的,传入一个复数对象,将结果保存在调用对象的数据中,并更改模长
void Complex::mut(const Complex& c);
-
共轭操作
调用对象的con()函数的,该操作只需要更改虚部的政府即可,实部、模长的数据不需要改
void Complex::con();
-
-
运行结果
- 第一部分为结构体complex的测试结果
- 第二部分为类Complex的测试结果
任务二
-
随机生成长度为10的浮点型的一位数组
- 随机生成一个浮点数的函数(在main函数中设置了srand(time(0)以保证每次得到的10个随机数完全不同)
double randnum(){//随机生成一个浮点数 return rand()/double(RAND_MAX)*1000; //为了使数据明显,将0-1的浮点数扩大1000倍 }
-
生成10个随机数
for循环执行10次,每次得到一个随机数,用数组存下来
-
使用直接插入排序的方法对数组进行排序
-
为了实现直接插入排序,创建数组时,创建num[11],把num[0]预留出来作为哨兵,可以防止越界(避免了越界检查)
-
从第二个数开始:先把位置i上的数放到num[0]中,再依次和前一个数比较,如果小于前一个数,那么就将前一个数填入到后一个数的位置,直到碰到第一个比它大的数,那么就将num[0]填入这个位置(重复以上操作)
关键代码:
for(int i=2;i<=10;i++){ x[0]=x[i];//设置哨兵,很好地避免了越界 int j=i; while(x[0] < x[j-1]){ x[j]=x[j-1];//把前一个数据放到这里 j--; } x[j]=x[0]; }
-
-
给出每一次插入排序后的排序效果,并给出最终的排序结果(如下图所示):
-
给出排序的最终结果以及算法复杂度
-
空间复杂度:O(n)
只需要存放数的一维数组的大小。
-
时间复杂度:O(n2)
该程序的时间复杂度主要由排序函数造成,在排序过程中,外部从2-n循环,内部从i到1循环,其余部分均为线性,据此简单来看时间复杂度是O(n2)。
任务三
-
用C++构建一个类,类成员函数包括矩阵相乘(m*n矩阵,用二维数组表示)、矩阵相加、矩阵转置以及矩阵求逆。
-
矩阵的类的定义
m行n列
为了方便调用,使用二维数组来表示矩阵,数字的类型定为double,开辟100*100的二维数组,已经可以表示常见的大多数矩阵
因为在定义时,设置了double num[100][100],所以要避免传参数的时候复制一份传过去,这里的形参采用了常引用的类型,既避免了拷贝花费太多的时间,同时能够保证数据的安全性
class Matrix{ public: int m;//m行n列的矩阵 int n; double num[100][100];//为了方便地使用二维数组,未使用vector高级 Matrix();//无参构造函数,构造一个空矩阵 Matrix(int m0,int n0);//两个参数的构造函数,构造一个有行有列的矩阵 ~Matrix(){} void add(const Matrix& m1,const Matrix& m2);//相加函数 void mut(const Matrix& m1,const Matrix& m2);//相乘函数 void tran(const Matrix& m1);//转置函数 void rebel(const Matrix& m1);//求m1的逆矩阵 void print();//打印当前矩阵 };
-
构造函数
在构造函数中设置矩阵的行列,以及矩阵中的数据,并且按行输入矩阵中的数据
由于形参设置成了常引用,而非值传递,在这里没有编写复制构造函数
Matrix::Matrix(); Matrix::Matrix(int m0,int n0):m(m0),n(n0);
-
析构函数
为了形成良好的习惯,写析构函数,提醒在有new的时候要delete
-
矩阵相加
检查行列数是否对应相等,如果不等直接结束,并给出错误信息,行列数相同时,对应项直接相加,行列数直接复制一份。
void Matrix::add(const Matrix& m1,const Matrix& m2){ if(m2.m!=m1.m||m2.n!=m1.n){ cout<<"不合法操作,矩阵维度不匹配"<<endl; return; } m=m1.m;n=m1.n; for(int i=1;i<=m1.m;i++) for(int j=1;j<=m1.n;j++) num[i][j]=m1.num[i][j]+m2.num[i][j];//对应项相加 cout<<"矩阵求和结果:"<<endl; print(); }
-
矩阵相乘
检查是否满足前一个矩阵的列数是否等于后一个矩阵的行数,如果不等直接结束,并给出相关的错误信息,如果满足前文中的条件,那么就按照矩阵的乘法进行计算,并更新行列数
void Matrix::mut(const Matrix& m1,const Matrix& m2){ //实现矩阵的乘法 if(m1.n!=m2.m){ cout<<"不合法操作,矩阵的维度不匹配"<<endl; return; } m=m1.m; n=m2.n; for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ double tmp=0; for(int k=1;k<=m1.n;k++){ tmp+=m1.num[i][k]*m2.num[k][j]; } num[i][j]=tmp; } } cout<<"矩阵求乘积结果:"<<endl; print(); }
-
矩阵转置
只要将行列数交换,并且按照对应的关系进行赋值即可。
void Matrix::tran(const Matrix& m1){ //完成矩阵的转置 m=m1.n; n=m1.m; for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) num[i][j]=m1.num[j][i]; cout<<"矩阵转置结果:"<<endl; print(); }
-
求逆矩阵
这里采用伴随矩阵的方式求逆矩阵
只有方阵(行列数相等)时,才可以求逆矩阵,在求逆矩阵前,先判断行列数是否相等,如果行列数不相等,那么可以直接返回,并提示错误信息
如果相等,那么就可以进行下一步
如果矩阵的对应的行列式的值为0,那么不可逆直接结束(矩阵不可逆条件),否则先求出来伴随矩阵,根据伴随矩阵求逆矩阵(注意伴随矩阵求的时候,要转置)
求行列式的值时,采用递归的思想求解,结束条件是对应的矩阵的秩为1
在求伴随矩阵时,调用求行列式的值的函数
//计算行列式A的值,只有方阵才谈论逆矩阵 double getA(const double x[][100],int n){ //递归求解A的行列式的值 if(n==1){//递归结束条件,只有一个值 return x[1][1]; } double num=0;//用来记录行列式的值 double tmp[100][100];//用来copy一份余子式对应的矩阵 for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) tmp[i][j]=0; } for(int i=1;i<=n;i++){//第i个 for(int j=1;j<n;j++){ for(int k=1;k<n;k++){ tmp[j][k]=x[j+1][k>=i?k+1:k];//复制一份,但是要避开i所在的那一列 } } double mid=getA(tmp,n-1); if(i%2){ num+=x[1][i]*mid;//奇数时,为正 } else{ num-=x[1][i]*mid;//偶数时,为负 } } return num;//返回计算结果 } void adjMat(const double x[][100],int n,double res[][100]){ //求伴随矩阵,求出伴随矩阵,那么逆矩阵就基本完成了 if(n==1){ res[1][1]=x[1][1]; return; } double tmp[100][100]; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) tmp[i][j]=0; } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){//外层循环用来检查 for(int k=1;k<n;k++){//内层循环用来copy出来代数余子式那部分对应的矩阵 for(int l=1;l<n;l++){ tmp[k][l]=x[k>=i?k+1:k][l>=j?l+1:l]; } } //计算代数余子树 res[j][i]=getA(tmp,n-1);//转置 if((i+j)%2&&res[j][i]!=0){ res[j][i]=-res[j][i]; } } } } void Matrix::rebel(const Matrix& m1){ //求矩阵的逆 if(m1.m!=m1.n){ cout<<"该矩阵不是方阵"<<endl; return; } double A=getA(m1.num,m1.n); if(!A){ cout<<"该矩阵不可逆"<<endl; return ; } adjMat(m1.num,m1.m,num);//结果存放在了新建的矩阵中 m=n=m1.n; for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++) num[i][j]/=A; } cout<<"矩阵的逆为:"<<endl; print(); }
-
-
调用类的函数进行测试,打印出结果。
任务四
-
提取其中的装甲板(蓝色框的内部的平行四边形)
-
画出找到的四边形并保存为“result.jpg”
一、思路一
该思路来自于文档矫正部分,找出面积最大的部分,并且符合该任务的目标-找到装甲板
- 利用findCountours函数识别所有轮廓
vector<vector<Point> >contours; vector<Vec4i>hierarchy;//寻找轮廓-成功存放在contours中 findContours(srcImg,contours,hierarchy,RETR_CCOMP,CHAIN_APPROX_SIMPLE);
-
由于装甲板的面积最大,尝试使用比较面积从而找到
max为装甲板(面积最大)轮廓的索引,contours[max]即代表装甲板的轮廓
int max=0; double maxArea=0; for(int i=0;i<contours.size();++i){ double area=contourArea(contours[i]); if(area>maxArea){ max=i; maxArea=area; } }
- 画出装甲板轮廓
//画出装甲板轮廓 drawContours(l,contours,max,Scalar(255,0,0),2);
- 画出包围装甲板的最小矩形
//画出最小矩形 RotatedRect ROI=minAreaRect(contours[max]); Point2f P[4]; ROI.points(P); for(int j=0;j<4;j++){ line(l,P[j],P[(j+1)%4],Scalar(0,0,255),2,8); }
-
结果如下:
-
保存结果
imwrite("./result.png",l);
二、思路二
只是在此作为考虑,由于时间原因,没有进行实现
任务中提示可以考虑漫水填充算法,在此进行考虑
- 利用findContours函数找到所有轮廓
利用漫水填充算法要求我们必须给出一个种子点,然后从此点进行漫水填充,但是这个点有没有一个比较好的方式得到
考虑以下方式:
- 把图片放到PS中,量取装甲板上的一个点,并将此点作为种子点
- 找到包围面积最大的那个轮廓(即思路一中的方式),取这个轮廓上的一个点作为种子点
- 取一个种子点
- 利用漫水填充 floodFill函数进行填充
任务五
-
进行一些基本的变换(平移,旋转,缩放),结果以png格式保存
- 平移
srcTriangle[0]=Point2f(0,0); srcTriangle[1]=Point2f(0,1); srcTriangle[2]=Point2f(1,0); //平移-设置向右平行50个单位; dstTriangle[0]=Point2f(50,0); dstTriangle[1]=Point2f(50,1); dstTriangle[2]=Point2f(51,0); warpMat=getAffineTransform(srcTriangle,dstTriangle);//得到变换矩阵
- 旋转
Point center=Point(dstImg_warp.cols/2,dstImg_warp.rows/2); double angle=-30.0; rotMat=getRotationMatrix2D(center,angle,1);//得到旋转的变化矩阵
- 缩放
double scale=0.7; rotMat=getRotationMatrix2D(center,0,scale);//得到缩放的变换矩阵
- 利用warpAffine函数进行求解整个图像变换后的图像
- 原图、平移、旋转、缩放依次如下图所示
-
识别一张倾斜拍摄的纸张,找出轮廓,提取纸张的位置
-
通过图像处理的算法找到了发生形变的纸张的位置,那么对这个倾斜的纸张进行变换,得到纸张垂直视图,实现文档校准
一、思路一
任务四的思路一救来源于这里
当然这里的思路借鉴了网上的想法
目前没有一种很好的方式确定轮廓,但是呢,由于手机拍摄出来的纸张都还是图像里面积最大的(因此,这里完全够用)
-
findContours函数找出所有轮廓
-
遍历contours,利用contourArea函数找到面积最大的轮廓,该轮廓大概率就是我们要找的轮廓(依据常识以及认为习惯来看–该结论还是很准的)
-
找到轮廓的四周的四个点,这里有三种方式
- 直接打开PS测量,但是受限制比较多
- 利用凸包进行计算:在利用convexHull函数寻找凸包前,先对所有轮廓利用approxPolyDP函数进行多边形逼近处理,这样能够比较好的得到一个边界比较直的轮廓,其实就是为了提高凸包计算时的准确性
- 确定输出图像的大小,利用getPerspectiveTransform函数求解透视变换的矩阵
Mat wrapMatrix=getPerspectiveTransform(srcpoint,dstpoint);
- 利用warpPerspective函数进行透视变换
warpPerspective(srcImg,dstImg_pers,wrapMatrix,dstImg_pers.size());
- 变换结果
二、思路二
霍夫变换直线检测,利用不平行的两直线相交于一点,求解文档的轮廓以及四个顶点,然后进行透视变换
霍夫变换的优势:能够克服纸张缺损的情况,比较强大
劣势:考虑的情况比较多,过程比较复杂
(还未进行验证)
-
任务六
-
对灰度图进行直方图均衡化,并将处理后的图片保存
直接调用equalizeHist
(当然前提是灰度图–这里读取的原图就是一张灰度图)
equalizeHist(srcImg,dst);
- 结果(上面是原图、下面是直方图均衡化后的图)
- 对恢复图的像素点进行统计,将统计的结果打印到屏幕上
- 调用calcHist函数统计直方图的信息
- 定义了getHistImage函数,在该函数内部实现了直方图的绘制
-
对RGB图像进行颜色空间转换,转换到HSV空间
cvtColor(s,s,COLOR_BGR2HSV);
任务七
之前了解过一点python,但并没有总结过,近期,在廖雪峰的官方网站学习python,并记录了一些没见过的知识点
python的基本语法基本掌握,但尚缺乏联系,不够熟练。
(笔记还未来得及进行格式整理,只是根据学习的一些内容,先快速过了一遍,为了减少占用的篇幅,在此将-python随笔-上传CSDN,随后再进行整理,由以下链接可进入)
https://blog.csdn.net/jingyu_1/article/details/120633348
(该博客也是我从上半年来使用至今的博客)
可以用python完成面向过程的编程,可以完成对类的编写,完成基础的面向对象编程。
看了一些网络资源,了解了一些相机标定的内容。
正常尝试安装Ubuntu系统,由于电脑存储空间不够,没有办法在当前电脑上装新系统或者装虚拟机,所以网购了一个三星的移动固态硬盘,打算尝试将Ubuntu系统安装到移动固态硬盘上,目前遇到一些困难,正在尝试。
附录
#include <iostream>
#include <math.h>
using namespace std;
//结构体相关函数
struct complex{
float len; //存放模长
float num[2]; //存放实部和虚部
};
void print(const complex& c){
cout<<c.num[0];
if(c.num[1]>=0)
cout<<"+";
cout<<c.num[1]<<"i";
cout<<"\t"<<"len="<<c.len<<endl;
}
complex add(const complex& c1,const complex& c2){
complex c;
c.num[0]=c1.num[0]+c2.num[0];
c.num[1]=c1.num[1]+c2.num[1];
c.len=sqrt(c.num[0]*c.num[0]+c.num[1]*c.num[1]);//模相乘
print(c);
return c;
}
complex mut(const complex& c1,const complex& c2){
complex c;
c.num[0]=c1.num[0]*c2.num[0]-c1.num[1]*c2.num[1];//实部
c.num[1]=c1.num[0]*c2.num[1]+c1.num[1]*c2.num[0];//虚部
c.len=c1.len*c2.len;
print(c);
return c;
}
complex con(const complex& c1){
complex c;
c.num[0]=c1.num[0];
c.num[1]=-c1.num[1];
c.len=c1.len;
print(c);
return c;
}
//类相关函数
class Complex{
private:
float len;
float num[2];
public:
Complex(float x,float y);
~Complex(){}
void add(const Complex& c);
void mut(const Complex& c);
void con();
void print();
};
Complex::Complex(float x,float y){
num[0]=x;
num[1]=y;
len=sqrt(x*x+y*y);
print();
}
void Complex::add(const Complex& c){
num[0]=num[0]+c.num[0];
num[1]=num[1]+c.num[1];
len=sqrt(num[0]*num[0]+num[1]*num[1]);
print();
}
void Complex::mut(const Complex& c){
num[0]=num[0]*c.num[0]-num[1]*c.num[1];
len=len*c.len;
print();
}
void Complex::con(){
num[1]=-num[1];
print();
}
void Complex::print(){
cout<<num[0];
if(num[1]>=0)
cout<<"+";
cout<<num[1]<<"i";
cout<<"\t"<<"len="<<len<<endl;
}
int main(){//测试
complex c,c1,c2;
cout<<"\n请输入 两个复数的 实部和虚部:\n";
cin>>c1.num[0]>>c1.num[1];
c1.len=sqrt(c1.num[0]*c1.num[0]+c1.num[1]*c1.num[1]);
cin>>c2.num[0]>>c2.num[1];
c2.len=sqrt(c2.num[0]*c2.num[0]+c2.num[1]*c2.num[1]);
cout<<"c1=";print(c1);
cout<<"c2=";print(c2);
cout<<"c1+c2=";c=add(c1,c2);
cout<<"c1*c2=";c=mut(c1,c2);
cout<<"c1的共轭:";c=con(c1);
cout<<"\n请输入 两个复数的 实部和虚部:\n";
float x1,x2,y1,y2;
cin>>x1>>y1>>x2>>y2;
cout<<"c1=";
Complex com1(x1,y1);
cout<<"c2=";
Complex com2(x2,y2);
cout<<"c1+c2=";
com1.add(com2);
cout<<"(c1+c2)*c2=";
com1.add(com2);
cout<<"c1*c2的共轭:";
com1.con();
return 0;
}
#include <iostream>
using namespace std;
double num[11];//单独空出来一个用作哨兵
double randnum(){
//随机生成一个浮点数
return rand()/double(RAND_MAX)*1000;//为了使数据明显,将0-1的浮点数扩大1000倍
}
void print(double x[],int n){
for(int i=1;i<n;i++){
cout<<x[i]<<" ";
}
cout<<endl;
}
void sort(double x[],int n){
//对数组进行排序
for(int i=2;i<=10;i++){
x[0]=x[i];//设置哨兵,很好地避免了越界
int j=i;
while(x[0] < x[j-1]){
x[j]=x[j-1];//把前一个数据放到这里
j--;
}
x[j]=x[0];
print(x,n);//按要求,每次都要输出结果
}
}
int main(){
srand(time(0));
for(int i=1;i<=10;++i){//随机生成10个浮点数
num[i]=randnum();
}
cout<<"初始数据:";
print(num,11);
cout<<endl;
sort(num,11);//对10个数进行排序,11中包括一个无值的哨兵
cout<<endl<<"排序结果:";
print(num,11);
return 0;
}
/**
* @Author: Your name
* @Date: 2021-09-22 20:34:26
* @Last Modified by: Your name
* @Last Modified time: 2021-10-07 10:14:10
*/
#include <iostream>
using namespace std;
class Matrix{
public:
int m;//m行n列的矩阵
int n;
double num[100][100];//为了方便地使用二维数组,未使用vector高级
Matrix();//构造一个空矩阵
Matrix(int m0,int n0);//构造一个有行有列的矩阵
~Matrix(){}
void add(const Matrix& m1,const Matrix& m2);
void mut(const Matrix& m1,const Matrix& m2);
void tran(const Matrix& m1);
void rebel(const Matrix& m1);
void print();
};
void Matrix::print(){
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
cout<<num[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
}
Matrix::Matrix(){
m=n=0;
cout<<"已构造一个空的矩阵,可以保存计算结果"<<endl<<endl;
}
Matrix::Matrix(int m0,int n0):m(m0),n(n0){
cout<<"请输入矩阵各行各列的值"<<endl;
for(int i=1;i<=m0;++i)
for(int j=1;j<=n0;++j)
cin>>num[i][j];
cout<<"输入的矩阵的为:"<<endl;
print();
}
void Matrix::add(const Matrix& m1,const Matrix& m2){
if(m2.m!=m1.m||m2.n!=m1.n){
cout<<"不合法操作,矩阵维度不匹配"<<endl;
return;
}
m=m1.m;n=m1.n;
for(int i=1;i<=m1.m;i++)
for(int j=1;j<=m1.n;j++)
num[i][j]=m1.num[i][j]+m2.num[i][j];//对应项相加
cout<<"矩阵求和结果:"<<endl;
print();
}
void Matrix::mut(const Matrix& m1,const Matrix& m2){
//实现矩阵的乘法
if(m1.n!=m2.m){
cout<<"不合法操作,矩阵的维度不匹配"<<endl;
return;
}
m=m1.m;
n=m2.n;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
double tmp=0;
for(int k=1;k<=m1.n;k++){
tmp+=m1.num[i][k]*m2.num[k][j];
}
num[i][j]=tmp;
}
}
cout<<"矩阵求乘积结果:"<<endl;
print();
}
void Matrix::tran(const Matrix& m1){
//完成矩阵的转置
m=m1.n;
n=m1.m;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
num[i][j]=m1.num[j][i];
cout<<"矩阵转置结果:"<<endl;
print();
}
//计算行列式A的值,只有方阵才谈论逆矩阵
double getA(const double x[][100],int n){
//递归求解A的行列式的值
if(n==1){//递归结束条件,只有一个值
return x[1][1];
}
double num=0;//用来记录行列式的值
double tmp[100][100];//用来copy一份余子式对应的矩阵
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
tmp[i][j]=0;
}
for(int i=1;i<=n;i++){//第i个
for(int j=1;j<n;j++){
for(int k=1;k<n;k++){
tmp[j][k]=x[j+1][k>=i?k+1:k];//复制一份,但是要避开i所在的那一列
}
}
double mid=getA(tmp,n-1);
if(i%2){
num+=x[1][i]*mid;//奇数时,为正
}
else{
num-=x[1][i]*mid;//偶数时,为负
}
}
return num;//返回计算结果
}
void adjMat(const double x[][100],int n,double res[][100]){
//求伴随矩阵,求出伴随矩阵,那么逆矩阵就基本完成了
if(n==1){
res[1][1]=x[1][1];
return;
}
double tmp[100][100];
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
tmp[i][j]=0;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){//外层循环用来检查
for(int k=1;k<n;k++){//内层循环用来copy出来代数余子式那部分对应的矩阵
for(int l=1;l<n;l++){
tmp[k][l]=x[k>=i?k+1:k][l>=j?l+1:l];
}
}
//计算代数余子树
res[j][i]=getA(tmp,n-1);//转置
if((i+j)%2&&res[j][i]!=0){
res[j][i]=-res[j][i];
}
}
}
}
void Matrix::rebel(const Matrix& m1){
//求矩阵的逆
if(m1.m!=m1.n){
cout<<"该矩阵不是方阵"<<endl;
return;
}
double A=getA(m1.num,m1.n);
if(!A){
cout<<"该矩阵不可逆"<<endl;
return ;
}
adjMat(m1.num,m1.m,num);//结果存放在了新建的矩阵中
m=n=m1.n;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++)
num[i][j]/=A;
}
cout<<"矩阵的逆为:"<<endl;
print();
}
int main()
{
//检验以上类和函数是否正确可行
Matrix m1(4,4);
Matrix m2(4,4);
Matrix m;
m.add(m1,m2);
m.mut(m1,m2);
m.tran(m1);
cout<<"矩阵的行列式"<<getA(m1.num,m1.n)<<endl;
m.rebel(m1);
return 0;
}
/**
* @Author: Your name
* @Date: 2021-09-29 20:11:36
* @Last Modified by: Your name
* @Last Modified time: 2021-10-07 17:17:12
*/
#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main(int argc, char const *argv[])
{
Mat srcImg;
//没有加0,出现的问题
srcImg=imread("/Users/liujingyu/Desktop/2022赛季狼牙算法组招新/2022算法组考核题目中需要的图片/task_4.png",0);
vector<vector<Point> >contours;
vector<Vec4i>hierarchy;
//寻找轮廓-成功存放在contours中
findContours(srcImg,contours,hierarchy,RETR_CCOMP,CHAIN_APPROX_SIMPLE);
Mat l=Mat::zeros(srcImg.rows,srcImg.cols,CV_8UC3);//C3三个通道才能画出蓝色,C1只能画出黑白
// for(int i=0;i<contours.size();++i)
// drawContours(line,contours,i,Scalar(255,0,0));//用蓝线把轮廓描绘出来
//imshow("result",line);
int max=0;
double maxArea=0;
for(int i=0;i<contours.size();++i){
double area=contourArea(contours[i]);
if(area>maxArea){
max=i;
maxArea=area;
}
}//找到了最大的轮廓
drawContours(l,contours,max,Scalar(255,0,0),2);
imshow("max",l);
waitKey(0);
RotatedRect ROI=minAreaRect(contours[max]);
//rectangle(line,ROI,Scalar(0,255,0),2);
Point2f P[4];
ROI.points(P);
for(int j=0;j<4;j++){
line(l,P[j],P[(j+1)%4],Scalar(0,0,255),2,8);
}
imshow("result",l);
waitKey(0);
imwrite("./result.png",l);
return 0;
}
#include <iostream>
#include <stdio.h>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char const *argv[])
{
Mat srcImg,dstImg_warp,dstImg_rotate;
Point2f srcTriangle[3];
Point2f dstTriangle[3];
Mat rotMat(2,3,CV_32FC1);
Mat warpMat(2,3,CV_32FC1);
//读取-要是完整的路径
srcImg=imread("/Users/liujingyu/Desktop/2022赛季狼牙算法组招新/2022算法组考核题目中需要的图片/task_5.png");
if(!srcImg.data){
printf("读取错误\n");
}
imshow("init",srcImg);
waitKey(0);
dstImg_warp=Mat::zeros(srcImg.rows,srcImg.cols,srcImg.type());
srcTriangle[0]=Point2f(0,0);
srcTriangle[1]=Point2f(0,1);
srcTriangle[2]=Point2f(1,0);
//平移-设置向右平行50个单位;
dstTriangle[0]=Point2f(50,0);
dstTriangle[1]=Point2f(50,1);
dstTriangle[2]=Point2f(51,0);
warpMat=getAffineTransform(srcTriangle,dstTriangle);
//对原图像应用仿射变换-实现了仿射变换
warpAffine(srcImg,dstImg_warp,warpMat,dstImg_warp.size());
imshow("平移",dstImg_warp);
waitKey(0);
Point center=Point(dstImg_warp.cols/2,dstImg_warp.rows/2);
double angle=-30.0;
rotMat=getRotationMatrix2D(center,angle,1);
warpAffine(srcImg,dstImg_rotate,rotMat,dstImg_warp.size());
imshow("旋转",dstImg_rotate);
waitKey(0);
double scale=0.7;
rotMat=getRotationMatrix2D(center,0,scale);
warpAffine(srcImg,dstImg_rotate,rotMat,dstImg_warp.size());
imshow("缩放",dstImg_rotate);
waitKey(0);
//以下为透视变换--且是针对给出的图片来进行的
//顺时针看-原图像的第一个点971,150,第二个点1693,245
//第三个点1236,979,第四个点236,632
Point2f srcpoint[4];
Point2f dstpoint[4];
srcpoint[0]=Point2f(971,150);
srcpoint[1]=Point2f(1693,245);
srcpoint[2]=Point2f(1236,979);
srcpoint[3]=Point2f(236,632);
dstpoint[0]=Point2f(0,0);
dstpoint[1]=Point2f(650,0);
dstpoint[2]=Point2f(650,900);
dstpoint[3]=Point2f(0,900);
Mat wrapMatrix=getPerspectiveTransform(srcpoint,dstpoint);
Mat dstImg_pers=Mat::zeros(900,650,srcImg.type());
warpPerspective(srcImg,dstImg_pers,wrapMatrix,dstImg_pers.size());
imshow("透视",dstImg_pers);
waitKey(0);
//一个点应该是肯定的-找到轮廓中面积最大的轮廓,一般就是我们所要找的ROI区域
return 0;
}
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
Mat getHistImage(const MatND &hist){
//MatND特制多维矩阵
double maxValue=0;
double minValue=0;
minMaxLoc(hist,&minValue,&maxValue,0,0);//找出最大值和最小值
int histSize=hist.rows;
Mat histImage(histSize,histSize,CV_8UC3,Scalar(255,255,255));//相当于创建一个直方图的画布
int hpt=static_cast<int>(0.9*histSize);
Scalar color(172,172,150);
for(int h=0;h<histSize;h++){
float binVal=hist.at<float>(h);
int intensity=static_cast<int>(binVal*hpt/maxValue);
line(histImage,Point(h,histSize),Point(h,histSize-intensity),color);
}
return histImage;
}
int main(int argc, char const *argv[])
{
Mat srcImg=imread("/Users/liujingyu/Desktop/2022赛季狼牙算法组招新/2022算法组考核题目中需要的图片/task_6.png",0);
if(srcImg.empty()){
cout<<"打开失败!"<<endl;
exit(-1);
}
imshow("原图",srcImg);
waitKey(0);
Mat dst;
equalizeHist(srcImg,dst);
imshow("均衡化",dst);
waitKey(0);
//现在画直方图-现在本身就是一个灰度图
int image_count=1;//1张图片
int channels[1]={0};//通道0
Mat out;
int dims=1;
int histsize[1]={256};//直方图横坐标的子区间数
float hrange[2]={0,256};//区间的总范围
const float *ranges[1]={hrange};//指针数组
calcHist(&srcImg,image_count,channels,Mat(),out,dims,histsize,ranges);
//计算直方图
Mat last=getHistImage(out);//画直方图的图像
imshow("result",last);
waitKey(0);
Mat s=imread("/Users/liujingyu/Desktop/视觉学习/u=2108319215,1494231136&fm=253&fmt=auto&app=120&f=JPEG.jpg");
imshow("BGR",s);
waitKey(0);
cvtColor(s,s,COLOR_BGR2HSV);
imshow("HSV",s);
waitKey(0);
return 0;
}