视觉识别
视觉识别
yolo模型
yolov1
- 如果时间充裕建议先学神经网络
- 结构:数据处理模块,网络模块,损失函数模块,训练模块,检测模块
- 个人yolov1理解:导入数据,网络识别,损失判断,权重调整,导出模型,图片识别
基本概念
- 数据保存:yolo模式,voc模式......具体百度,不重要
- 图片预处理:对图片进行增强,反转,调色,应该是有利于训练时起到减轻过拟合作用,同时变相的加多了训练轮数,但是数据够多没啥必要好像(无数据依据)
- 卷积:从图像提取特征,但具体只有计算机知道了,有逆卷积相关论文
- 特征:可以是局部的特征也可以是总体的特征,比如爪子的形状,总体颜色色调,我的理解是本质还是用图像11对照,但是这个对照的方面比较多,在整张图去寻找很多个特征图,找到了就加符合概率,比如找爪子,找红色,找圆形的轮廓,可能会进行放大处理(理论上算的过来的话最好是缩放都试一下)
- 池化:平均池化和最大池化,筛选特征
- 全连接:把所有提取出的特征连接起来
- 网络:一堆池化卷积加全连接
- 权重:卷积核操作时的占比吧,还是直接调整卷积核,并不清楚
- pth:文件,按之前训练的网络格式存储的对应权重,所以导入pth文件时的训练模块需要匹配
- 预训练模型:理解为针对各种基础特征训练过的模型,可以较快的进行通用特征提取
yolov1实现
- 毕竟是12年的东西,没找到很多的模拟实现代码
- 本质上就是在网络识别上做了些trick,并不是什么底层技术突变,主要还是依赖于神经网络(聪明,但没到创世)
- 大致流程
- 数据处理模块将所有图片和标签合并为\(7*7*(类别+10)\)的张量
- 导入模型,同时在模型参数上做些改动(然而我并没有改懂),主要目的是能够输入一张图片在提取特征并将特征与权重相匹配操作后,输出\(7*7*(类别+10)\)的张量
- 定义损失:在判断误差大小的同时,用于调整权重,可操作的点是根据需要可以个性化选择要提取的特征
- 定义优化:防止失去梯度,loss瞎跑,使学习逐步稳定,防止已经学习到的特征丢失
- 训练:
- 循环检测图片:
- 通过网络得到检测结果,位置和类别信息
- 将检测结果与实际信息对比,计算损失
- 计算梯度,我的理解是,对于统一的特征而言,从上一张图片下来,对于共同特征而言,改进的方向是一样的也就是梯度方向一样,最终会随着越来越接近特征而梯度减小
- 更新权重,为下一次检测做改进,如果效果不好,梯度为负就回退改进,梯度计算应该是有惯性的,不会每张改变特别大
- 去检测训练集,但不再改变训练权重
- 循环检测图片:
- 保存权重
yolov1的开创之处
- 分割检测,将神经网络的负担分担到数据处理上,减小了部分计算量,算法的复杂度没变,但是每个循环的计算量变小
- 极大值抑制,nms/ioc,有效的使检测框减少,但是并没有减小计算量
- 还是很牛逼了的
mininconda环境配置
GPU需要安装cuda和cunna,不自带的
教程:https://blog.csdn.net/qq_45945548/article/details/121090907
https://www.cnblogs.com/wdysblog/p/16654592.html
https://blog.csdn.net/qq_51208442/article/details/125709001
pyrcc5 -o libs/resources.py resources.qrc这条命令需要pip install PyQt5-tools
conda info --envs#查看当前拥有的虚拟环境
conda activate xxxx #激活虚拟环境
conda create --prefix=C:/ProgramData/Anaconda3/envs/xxxxx python==3.8.2#指定位置创建虚拟环境
#上面那条然并软,conda使用约定优于配置,虚拟环境需要放在canda\envs目录下或者用户的.conda\envs目录下,不然没有名字,没法激活,用作解释器应该行
conda create -n xxxx python==3.8.2#在用户目录下创建虚拟环境
conda remove -n xxxx --all #删除环境
conda deactivate#退出虚拟环境
#教学链接https://blog.csdn.net/adreammaker/article/details/123396951
# 添加指定源
conda config --add channels * #*指代你要添加的源
# 设置安装包时,显示镜像来源,建议显示
conda config --set show_channel_urls yes
# 删除指定源
conda config --remove channels * #*代表你要删除的源
conda config --remove-key channels#删除所有镜像源
遇到的问题
failed with initial frozen solve. Retrying with flexible solve.
-
环境不适配
# 查看版本 conda -V # 更新conda环境 conda update -n base conda # 更新conda的所有包 conda update --all
-
EnvironmentNotWritableError: The current user does not have write permissions to the target environment.
- conda没有设置用户读写权限
OPENCV
基本数据结构
- Vec
- 向量的模板类,和数组差不多用法,可以加减乘除
Vec<double, 19> myVector
一个存储19个double类型向量的容器
- Point
- 表现了二维数组下的点
Point point1; point1.x = 10; point1.y = 8; Point point2 = Point(10, 8 );
- 几个别名
typedef Point_<int> Point2i;//整数类型 typedef Point2i Point; //整数类型 typedef Point_<float> Point2f; //浮点类型 typedef Point_<double> Point2d; //双精度类型
- Scalar
- Vec的派生类,有四个元素,用于传递和读取像素值,只需要三个参数的话写三个就行.
Scalar(b, g, r)
- Size
- 指定图像或矩形的大小,有两个成员width和height,使用area()计算面积
- Rect
- 矩形表示,有成员变量
x,y,width,height
分别表示左上角的坐标和矩形的宽和高
- 矩形表示,有成员变量
Size() //返回值为 Size ;
area() //返回矩形的面积;
contains(Point) //判断点是否在矩形内;
inside(Rect) //函数判断矩形是否在该矩形内;
tl()// 返回左上角点坐标;
br() //返回右下角点坐标。
+ 可以通过`&,|,+`来求矩阵交并集以及移动矩形,同时Rect可以确定图像区域
Mat img = imread("demo.jpg");
Rect r(0, 0, 100, 100);
Mat img_roi = img(r);
- RotateRect
class CV_EXPORTS RotatedRect { public: //构造函数 RotatedRect(); RotatedRect(const Point2f& center, const Size2f& size, float angle); RotatedRect(const CvBox2D& box); void points(Point2f pts[]) const;//!返回矩形的4个顶点 Rect boundingRect() const; //返回包含旋转矩形的最小矩形 operator CvBox2D() const; //!转换到旧式的cvbox2d结构 Point2f center; //矩形的质心 Size2f size; //矩形的边长,长宽的大小随机 float angle; //旋转角度,-0~-90,即都是逆时针 // 处于'/'状态时宽>高,处于'\'状态时高大于宽 };
- Mat
- 用于表示单通道或多通道的稠密数组,主要用于存储图像
Mat {
public:
template<typename _Tp> _Tp& at(int row, int col);//返回像素
int dims; //维数
int rows,cols; //行列数
uchar *data; //存储数据的指针
int *refcount; //引用计数
}
- 通道:一个像素点的数据,一通道灰度图,二通道用于数据处理,三通道HSV,RGB,四通道RGBA,加上透明度数据
- mat创建
//创建长宽为2,格式为CV_8UC3,(8位无符号,通道数为3),通道值为(0,0,255)的矩阵;
Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));
//所有通道为0;
Mat Z = Mat::zeros(3, 3, CV_64F);
//第一个通道为1,其余为0;
Mat F = Mat::ones(2, 2, CV_64F);
Mat M0(1,2,CV_8UC3);
float K[3][3] = {1, 0, 1, 0, 1, 1, 0, 0, 1};
Mat M1 = Mat(3,3,CV_32FC1,K);
基本函数
图片视频处理
- 图像读取
imread()
Mat imread( const String& filename, int flags = IMREAD_COLOR );
- filename为图像文件路径
- falgs是图像解析方式
IMREAD_UNCHANGED | 不对图像文件进行任何转换,直接读取 |
---|---|
IMREAD_GRAYSCALE | 将任何图像均转换为灰度图像(单通道)进行读取 |
IMREAD_COLOR | 将任何图像均转为RGB彩色图像(三通道)进行读取 |
IMREAD_ANYDEPTH | 如果不设置这个参数,16/32位图像将会自动转为8位图像 |
IMREAD_ANYCOLOR | 将按照图像文件设定的颜色格式进行图像读取 |
IMREAD_LOAD_GDAL | 调用gdal库进行图像文件读取(可以简单地理解为读取TIFF图像文件) |
- 图像显示
imshow()
void imshow(const String& winname, InputArray mat);
- 名称,图像.
- 只支持8位灰度图像、8位彩色图像和32位灰度图像(像素值范围0-1)
- 图像保存
imwrite()
bool imwrite( const String& filename, //保存名称 InputArray img, //保存图片 const std::vector<int>& params = std::vector<int>()); //特定格式保存编码
- 图像大小变换
resize()
void cv::resize (InputArray src, OutputArray dst, Size dsize, double fx = 0, //和diseze选一个用,fx,fy表示放大倍数 double fy = 0, int interpolation = INTER_LINEAR )
+ 视频读取和保存 www.baidu.com
#### 颜色空间转换 cvtColor()
+ `void cvtColor(InputArray src,outputArray dst,int code,int dstCn=0)`
+ 实现颜色空间转换,src:输入,dst:输出,code:转换方式,dstCn:目标通道数(为0取输入通道数)
```cpp
//此处是显示部分,总体就是加2的事
RGB<->BGR COLOR_RGB2BGRA,COLOR_BGRA2RGBA
RGB<->Gray COLOR_RGB2GRAY,COLOR_GRAY2RGB
RGB<->HSV COLOR_RGB2HSV,COLOR_HSV2RGB
二值化 threshold()
double cv::threshold(InputArray src, OutputArray dst, double thres, double maxval, int type)
- src:源图像,dst:输出,thresh:阈值;maxval:处理后灰度最大值;type:操作类型
标记 含义 THRESH_BINARY 灰度值超过阈值的像素设置为最大灰度值,不超过的设置为0 THRESH_BINARY_INV 灰度值不超过阈值的像素设置为最大灰度值,超过的设置为0 THRESH_TOZERO 灰度值低于阀值的像素设为0灰度值 THRESH_TOZERO_INV 灰度值高于阀值的像素设为0灰度值 THRESH_TRUNC 灰度值超过阈值的像素设为阈值的灰度值 THRESH_MASK 掩码 THRESH_OTSU 标记,使用大津算法来选择最佳阈值,只支持8位单通道图像 THRESH_TRIANGLE 标记,使用TRIANGLE算法来算则最佳阈值,只支持8位单通道图像
寻找边界 findContours()
void findContours(InputArray image,OutputArrayOfArrays contours, OutputArray hierarchy,int mode,int method,Point offset = Point())
- image:输入,八位单通道,背景为黑色的二值图像
- contours:输出,每个元素是一个轮廓,轮廓上包含众多点
- hierarchy:各个轮廓之间的继承关系,和contours对应,每个元素有四个整型向量
- mode:检测轮廓的方法
- RETR_EXTERNAL:只检测外轮廓。忽略轮廓内部的洞。
- RETR_LIST:检测所有轮廓,但不建立继承(包含)关系。
- RETR_TREE:检测所有轮廓,并且建立所有的继承(包含)关系。
- RETR_CCOMP:检测所有轮廓,但是仅仅建立两层包含关系。
- method:轮廓的编码信息
- CHAIN_APPROX_NONE:把轮廓上所有的点存储。
- CHAIN_APPROX_SIMPLE:只存储轮廓上的拐点。
- CHAIN_APPROX_TC89_L1,CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
- Point:偏移量,默认0
- 共同食用:
drawContours(
InputOutputArray binImg, // 输出图像
OutputArrayOfArrays contours,// 全部发现的轮廓对象
Int contourIdx// 轮廓索引号,-1表示绘制所有轮廓
const Scalar & color,// 绘制时候颜色
int thickness,// 绘制线宽,-1表示填充轮廓内部
int lineType,// 线的类型LINE_8
InputArray hierarchy,// 拓扑结构图
int maxlevel,// 最大层数, 0只绘制当前的,1表示绘制绘制当前及其内嵌的轮廓
Point offset = Point()// 轮廓位移,可选
)
contourArea(contour, oriented = False) //计算轮廓的面积
//contour为单个轮廓值,oriented为flase时返回面积绝对值,true时,轮廓方向为顺时针则为正,逆时针为负
arcLength(contour, closed) // 计算轮廓的周长
//也是单个轮廓,closed表示是否封闭(true为闭,false为开)
Moments m = moments(contours[t]); //获取轮廓的距
//计算轮廓质心
double cx = m.m10 / m.m00;
double cy = m.m01 / m.m00;
Rect rect = boundingRect(Mat(contours[i]));//获取轮廓外接正矩形
RotatedRect rect = minAreaRect(contours[i]);//获取轮廓最小外接矩形
Point2f P[4];
rect.points(P);//获取四顶点坐标
double pointPolygonTest(InputArray contour,Point2f pt, bool measureDist MeasureDist)
//轮廓点集合
//图像上任一点
//如果是True,则返回每个点到轮廓的距离,如果是False则返回+1,0,-1三个值,其中+1表示点在轮廓内部,0表示点在轮廓上,-1表示点在轮廓外
最小外接圆/拟合圆,拟合椭圆,拟合直线,轮廓凸包,多边形逼近
https://blog.csdn.net/weixin_50016546/article/details/125588721
split()和merge()
-
void split(const Mat& src, Mat*mvbegin);
-
void split(InputArray m,OutputArrayOfArrays mv);
-
两个都是把前一个多通道划分到后几个单通道去
-
void merge(const Mat* mv, size_tcount, OutputArray dst);
-
size_tcount 表示合并后通道数
-
void merge(InputArrayOfArrays mv,OutputArray dst);
-
合并
透视变换 getPerspectiveTransform()
Mat cv::getPerspectiveTransform (const Point2f src[], //原坐标点(3个及以上)
const Point2f dst[], //转换后坐标点
int solveMethod = DECOMP_LU //透视变换方法
)
solveMethod参数 | 作用 |
---|---|
DECOMP_LU | 最佳主轴元素的高斯消元法 |
DECOMP_SVD | 奇异值分解(SVD)方法 |
DECOMP_EIG | 特征值分解法 |
DECOMP_CHOLESKY | cholesky分解法 |
DECOMP_QR | QR分解法 |
DECOMP_NORMAL | 使用正规方程公式,可以和前面的标志一起用 |
void cv::warpPerspective(InputArray src, //输入图像
OutputArray dst, //输出图像
InputArray M, //变换矩阵
Size dsize, //输出图像尺寸
int flags = INTER_LINEAR, //插值方法
int borderMode = BORDER_CONSTANT, //像素边界外推方法的标志
const Scalar & borderValue = Scalar() //填充边界使用的数值
)