相机模型:小孔成像模型
单目相机:丢失深度信息,只能知道投影坐标
小孔成像模型——成像平面到像素坐标(一次缩放+一次平移)“相机内参K”——相机位姿,世界坐标系变换到相机坐标系 “相机外参R,t / T”
齐次坐标乘上任意常数表达意义不变——投影方程意义:(P为投影坐标,相机坐标系)
改变Z时,投影点仍是同一个
归一化处理:投影过程也可看为归一化平面上的点量化测量
畸变模型:径向畸变和切向畸变,用多项式表达
单目相机成像过程:
1.世界坐标系中点P,世界坐标Pw
2.相机运动,P的相机坐标Pc由R,t或T转换描述
3.相机坐标Pc投影到归一化平面(Z=1)处,得到归一化坐标Pcz
4.若有畸变,根据畸变参数计算Pcz畸变后的校正坐标Pczd
5.归一化坐标经过内参后,对应到像素坐标Puv=K*Pczd
图像:
像素坐标(x, y),访问图像像素:
unsigned char pixel = image[y][x];
- 灰度图:0-255,8位整数
- 深度图:0-65538,16位
- 彩色图:OpenCV:BGR,每个通道8位,总共24位
(彩色图三通道取平均,变为灰度图)
概念
B站链接
像素 :二进制图像:黑白,0/1
分辨率2^8=256,0黑255白
实践:OpenCV
头文件
#include<opencv2/opencv.hpp>
#include <opencv4/imagcodecs.hpp>
#include <opencv4/highgui/highgui.hpp>//GUI
#include <opencv4/imgproc.hpp>//图像处理
#include <iostream>
using namespace cv;
using namespace std;
读取图片、视频、网络相机
void main(){
string path = "Resources/test.png";
//导入图片
Mat img = imread(path);
//读取图片 Mat-opencv中的图像的矩阵数据类型
imshow("Image",img);
//显示图像,但会自动关闭
waitKey(0);//添加延时,打开不会关闭
}
void main(){
VideoCapture cap(0);//连接网络摄像头webcam,改为ID号
Mat img;
while(true){
cap.read(img);
imshow("Image",img);
waitKey(1);
}
}
图像处理:颜色转换、高斯模糊、坎尼边缘检测
高斯模糊,坎尼边缘检测
高斯模糊:高斯滤波去除图像噪声。图像平滑处理,均值滤波,高斯函数卷积加权。一般5×5,高斯核越大,对噪声越不敏感。
边缘检测:梯度双阈值检测。阈值越小,捕捉边缘信息越多
void main(){
string path = "Resources/test.png";
Mat img = imread(path);
Mat imgGray,imgBlur;
cvtColor(img,imgGray,COLOR_BGR2GRAY);
GaussianBlur(img,imgBlur,Size(7,7),5,0);//原图,现图,高斯矩阵尺寸,x轴高斯核标准差,y轴高斯核标准差
Canny(imgBlur,imgCanny,50,150);
}
图像膨胀、腐蚀
改变边缘厚度。边缘检测后,将边缘加粗或变细。
还是有点不理解膨胀和腐蚀
Mat kernel=getStructingElement(MORTH_RECT,Size(5,5));//内核形状(矩形、交叉形、椭圆形),内核尺寸,(锚点位置(偏移))
dilate(imgCanny,imgDil,kernel);
erode(imgDil,imgErode,kernel);
}
调整大小、裁剪
cout<<img.size();
resize(img,imgResize,Size(640,480));
resize(img,imgResize,Size(),0.5,0.5);
Rect roi(100,100,300,250);//定义矩形
imgCrop=img(roi);//在x=100,y=100的位置裁剪宽300,高250的图像
}
创建图案:圆、矩形、线、文本
Mat img(512,512,CV_8UC3,Scalar(255,0,0));//定义颜色一般用标量
circle(img,Point(256,256),155,Scalar(0,69,255),10);//图片,中心点,半径,颜色,边缘厚度(填充,FILLED)
rectangle(img,Point(130,226).Point(382,286)Scalar(255,255,255),FILLED);//左上点、右下点
line(img,Point(130,296).Point(382,450),Scalar(255,255,255),2);
putText(img,"Murtaza's Workshop",Point(137,262),FONT_HERSHEY_DUPLEX,0.75,Scalar(0,69,255),2);
提取图案鸟瞰图
string path="Resources/cards.jpg";
Mat img=imread(path);
float w=250,h=350;
Mat matrix,imgWarp;
Point2f src[4]={{529,142},{771,190},{405,395},{674,457}};// point2f 定义浮点型,取图1变换前四个顶点
Point2f dstc[4]={{0.0f,0.0f},{w,0.0f},{0.0f,h},{w,h}};//图2变换后四个顶点
matrix=getPerspectiveTransform(src,dst);//求透视变换矩阵
warpPerspective(img,imgWarp,matrix,Point(w,h));//透视变换创建鸟瞰图 原始图片,现图片,透视矩阵,尺寸
for(int i=0;i<4;i++){
circle(img,src[i],10,Scalar(0,0,255),FILLED);
}
检测图像颜色
人眼对于这三种颜色分量的敏感程度是不一样的,在单色中,人眼对红色最不敏感,蓝色最敏感,所以 RGB 颜色空间是一种均匀性较差的颜色空间。如果颜色的相似性直接用欧氏距离来度量,其结果与人眼视觉会有较大的偏差。对于某一种颜色,我们很难推测出较为精确的三个分量数值来表示。
所以,RGB 颜色空间适合于显示系统,却并不适合于图像处理。
在图像处理中使用较多的是 HSV 颜色空间,它比 RGB 更接近人们对彩色的感知经验。非常直观地表达颜色的色调、鲜艳程度和明暗程度,方便进行颜色的对比,常用于分割指定颜色的物体。(颜色特征明显时可进行图像分割)
HSV 表达彩色图像的方式由三个部分组成:
- Hue(色调、色相)
- Saturation(饱和度、色彩纯净度)
- Value(明度)
string path="Resources/lambo.png";
Mat img=imread(path);
Mat imgHSV,mask;
int hmin=0,smin=110,vmin=153;
int hmax=19,smax=240,vmax=255;
cvtColor(img,imgHSV,COLOR_BGR2HSV);//转换到HSV空间更容易检测颜色
Scalar lower(hmin,smin,vmin);
Scalar upper(hmax,smax,vmax);
inRang(imgHSV,lower,upper,mask);
创建跟踪栏
使用颜色进行目标检测和追踪
H: 0 — 180
S: 0 — 255
V: 0 — 255
namedWindow("Trackbars",(640,200));//创建滑动空间所在窗口
createTrackbar("Hue Min","Trackbars",&hmin,179);//滑动空间名称,滑动空间所在窗口,初始化阈值(不是最小值),最大值
createTrackbar("Hue Max","Trackbars",&hmin,179);
createTrackbar("Sat Min","Trackbars",&smin,255);
createTrackbar("Sat Max","Trackbars",&smin,255);
createTrackbar("Val Min","Trackbars",&vmin,255);
createTrackbar("Val Max","Trackbars",&vmin,255);
while(true){
Scalar lower(hmin,smin,vmin);
Scalar upper(hmax,smax,vmax);
inRang(imgHSV,lower,upper,mask);//二值化:主要是将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0)
}
检测图像、图像轮廓
预处理
转为灰度图——去噪——边缘检测——膨胀
string path = "Resources/test.png";
Mat img = imread(path);
Mat imgGray,imgBlur,imgCanny,imgDil;
cvtColor(img,imgGray,COLOR_BGR2GRAY);
GaussianBlur(imgGray,imgBlur,Size(3,3),3,0);
Canny(imgBlur,imgCanny,25,75);
Mat kernel=getStructingElement(MORTH_RECT,Size(3,3));
dilate(imgCanny,imgDil,kernel);