OpenCV学习(持续更新)
图像读取和输出
Mat image=imread("");
imshow(const String & winname,InputArraymat)
Mat image=imread("huaqiangmaigua.jpg");
imshow("华强买瓜",image);//第一个参数为窗口名称 第二个参数为变量
读取图像并且以灰度图显示
Mat src = imread("图片地址",IMREAD_GRAYSCALE);
读取图像并转换为三通道彩色图像
image=cv::imread("",CV_LOAD_IMAGE_COLOR);
或
image=imread("",IMAGE_COLOR);
存储照片
imwrite("output.bmp",result);
创建窗口
// 创建滑动块窗口
String winname("inRange");
namedWindow(winname, WINDOW_AUTOSIZE);
时延waitKey
waitKey(time) 在显示视频和调用摄像头的时候有用
waitKey(0); //一直显示这张图片
waitKey(30); //30ms后显示下一张图片
调用摄像头实例
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void main()
{
VideoCapture cap(0);
Mat img;
while(1)
{
cap>>img;//cap读取的图像流到img之中
imshow("my picture",img);
waitKey(30);
}
}
vector 容器
- vector是向量类型,可以容纳许多类型的数据,因此也被称为容器
- (可以理解为动态数组,是封装好了的类)
- 进行
vector
操作前应添加头文件#include
//先对其进行初始化
vector<Mat>mannels;
vector<int>box;
vector<int>a;
//定义具有10个整型元素的向量(尖括号为元素类型名,它可以是任何合法的数据类型),不具有初值,其值不确定
vector<int>a(10);
//定义具有10个整型元素的向量,且给出的每个元素初值为1
vector<int>a(10,1);
图像色彩通道转化
色彩空间
常用的色彩空间:
- bgr:3个通道
- gray:灰度图,1个通道
- bgra:4个通道,最后一个通道是透明度
色彩空间转换
cvtColor(src,dst,code,dstCn=None);
//src:要转化的图片对象
//dst:转化为的图片
//code:转化类型
//dstCn:COLOR_... 输出的通道数,0为自动获取src的通道数(可不写)
split函数
实现通道分离,BGR:blue green red box[0] box[1] box[2]
void main()
{
Mat image=imread("图片地址");
vector<Mat>box; //box为名称可变的一个存储器
split(image,box);//生成三张灰度图(即三个通道的图片) 越量的地方表示该处颜色最深
imshow("通道一",box[0]);
waitKey(0);
}
通道相减:提取目标对象的处理方法
Mat img;
img=channels[0]-channels[1];
imshow("通道相减1 蓝-绿",img;


blur均值滤波 为线性滤波
medianBlur 中值滤波
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
VideoCapture mp4;
mp4.open("video.path");
Mat frame;
Mat blur,blur1;
while(1)
{
char c;
mp4>>frame;
cv::blur(frame,blur,Size(20,20));//均值滤波
cv::medianBlur(frame,blur1,5);//中值滤波
//namedWindow("华强买瓜(原版)",WINDOW_NORMAL);//使得窗口可以更改大小
//namedWindow("华强买超糊瓜(均值滤波)",WINDOW_NORMAL);
//namedWindow("华强买微糊瓜(中值滤波)",WINDOW_NORMAL);
imshow("华强买瓜(原版)",frame);
imshow("华强买超糊瓜(均值滤波)",blur);
imshow("华强买微糊瓜(中值滤波)",blur1);
waitKey(30);
}
return 0;
}
阈值处理
threshold()函数
函数原型
/**
* @brief 对图像进行阈值处理,生成二值图
* @param src 输入图,只能输入单通道图像,通常是灰度图
* @param dst 输出图
* @param thresh 阈值
* @param maxval 当像素值大于(或小于,由type决定),所赋予的值
* @param type 二值化操作的类型,包含一下5种类型: THRESH_BINARAY, THRESH_BINARY_INV, THRESH_TRUNC, THRESH_TOZERO, THRESH_TOZERO_INV, (THRESH_OTSU)
* @return thresh的值
*/
double cv::threshold(cv::InputArray src, cv::OutputArray dst, double thresh, double maxval, int type);
- THRESH_BINARY 当前点值大于阈值时,取Maxval(也就是第四个参数,下面再不说明),否则设置为0
- THRESH_BINARY_INV 当前点值大于阈值时,设置为0,否则设置为Maxval
- THRESH_TRUNC 当前点值大于阈值时,设置为阈值,否则不改变
- THRESH_TOZERO 当前点值大于阈值时,不改变,否则设置为0
- THRESH_TOZERO_INV 当前点值大于阈值时,设置为0,否则不改变
tips: INV 意为反转
代码实例
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image=imread("图片地址",IMREAD_GRAYSCALE);
Mat new1,new2,new3,new4,new5,new6;
int thresh=127;
//进行阈值处理
threshold(image,new1,thresh,255,THRESH_BINARY);
threshold(image, new2, thresh, 255, THRESH_BINARY_INV);
threshold(image, new3, thresh, 255, THRESH_TRUNC);
threshold(image, new4, thresh, 255, THRESH_TOZERO);
threshold(image, new5, thresh, 255, THRESH_TOZERO_INV);
imshow("原图像", image);
imshow("BINARY",new1);
imshow("BINARAY_INV", new2);
imshow("TRUNC", new3);
imshow("TOZERO", new4);
imshow("TOZERO_INV", new5);
waitKey(300000);
return 0;
}
阈值的设置不同可以实现突出黑色或突出白色等其他颜色
inRange()函数
tips: 一般用于处理HSV图,但不限于HSV,也可以处理其他色彩通道的图片,如:BGR、GRAY,可以自己尝试效果
函数原型
/**
* @brief 检查数组元素是否位于两个数组元素值区间内,位于中间设为255,否则为0
* @param src 输入图
* @param lowerb 下边界的数组或标量
* @param upperb 上边界的数组或标量
* @param dst 输出的二值图
*/
void cv::inRange(cv::InputArray src, cv::InputArray lowerb, cv::InputArray upperb, cv::OutputArray dst)
eg: inRange(image,Scalar(10,10,10),Scalar(60,60,60),inRange_image);
other 其他方式
除了上述调用函数API的方法,我们还可以利用OpenCV中重载了的运算符进行二值化(通常使用灰度图)
binary = gray > 150; // 大于150设为255,否则为0
threshold(gray, binary, 150, 255, THRESH_BINARY);
binary = gray < 150; // 小于150设为255,否则为0
threshold(gray, binary, 150, 255, THRESH_BINARY_INV);
binary = gray == 150; // 等于150设为255,否则为0
滑动条的创建以及使用
创建滑动条
/**
* @brief 可以创建一个滑动条,并将滑动条附加到指定窗口上,常常需要和一个回调函数(onChange)配合使用,我们常将它用于调试参数
* @param trackbarname 滑动条的名字,用于代表我们所创建的滑动条
* @param winname 窗口名字,表示滑动条所依附的窗口
* @param value 一个指向整型的指针,表示滑块的位置。在创建时,滑块的初始位置就是该变量的当前值。
* @param count 表示滑块可以达到的最大值
* @param onChange 回调函数,有默认值0。每次滑块改变位置时,这个函数都会进行回调。并且这个函数的原型必须是 void XXXXX(int, void*);这两个参数分别对应了 value 和 userdata,相当于将这两个指针变量作为参数传递给回调函数。如果回调函数是 NULL,则表示没有回调函数的使用,仅第三个参数 value 有变化。
* @param userdata 一个指针,有默认值0,作为参数传递给 onCHange,一般用不到
*/
int cv::createTrackbar(const cv::String &trackbarname,
const cv::String &winname,
int *value, int count,
cv::TrackbarCallback onChange = (cv::TrackbarCallback)0,
void *userdata = (void *)0);
代码实例
//创建滑动条参数
int H,S,V;
int minH=0,minS=0,minV=0;
int myH,myS,myV;
//创建滑动条
createTrackbar("H",winname,&minH,255,NULL);
createTrackbar("S",winname,&minS,255,NULL);
createTrackbar("V",winname,&minV,255,NULL);
获取当前滑动条的位置:getTrackbarPos()函数
/**
* @brief 获取当前滑动条的位置并返回
* @param trackbarname 表示滑动条的名字
* @param winname 表示滑动条所在窗口的名字
* @return 返回滑块所在位置的值
*/
int cv::getTrackbarPos(const cv::String &trackbarname, const cv::String &winname)
形态学滤波
腐蚀与膨胀
/**
* @brief 膨胀操作
* @param kernel 操作核,可通过getStructuringElement()函数获得
*/
void cv::dilate(cv::InputArray src, cv::OutputArray dst,
cv::InputArray kernel,
cv::Point anchor = cv::Point(-1, -1), int iterations = 1, int borderType = 0, const cv::Scalar &borderValue = morphologyDefaultBorderValue())
/**
* @brief 腐蚀操作
*/
void cv::erode(cv::InputArray src, cv::OutputArray dst,
cv::InputArray kernel,
cv::Point anchor = cv::Point(-1, -1), int iterations = 1, int borderType = 0, const cv::Scalar &borderValue = morphologyDefaultBorderValue())
// 构造结构元素
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(5,5));
// 用结构元素对src进行膨胀和腐蚀处理
dilate(src, Dilate, element);
erode(src, Erode, element);

开闭运算
开运算:先腐蚀后膨胀,可以去除毛边
闭运算:先膨胀后腐蚀,可以填补小空缺
tips: OpenCV中也提供了相应的API函数接口 morphologyEx(),可以直接使用
计算轮廓面积
函数原型
double contourArea( InputArray contour, bool oriented = false );
- InputArray类型的contour,输入的向量,二维点(轮廓顶点),可以为std::vector或Mat类型。
- bool类型的oriented,面向区域标识符。若其为true,会返回一个带符号的面积值,正负取决于轮廓的方向。默认值为false
代码实例
Canny(grayImage, edge_image, 20, 100, 3,false);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(edge_image, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
for (int i = 0; i < contours.size(); i++)
{
cout << i<<":"<<abs(contourArea(contours[i])) << endl;
}
寻找轮廓并且绘制轮廓
寻找轮廓
/**
* @brief 用于在二值图中寻找轮廓
* @param image 输入图像,需为8位单通道图像(8UC1)。图像非0像素被视为255,0像素值被保留为0。我们可以用 threshold(), inRange(), canny(), compare()等函数由灰度图或彩色图像创建二值图。
* @param contours 检测到的所有轮廓,函数调用后的运算结果存在这里。每个轮廓都是一个点向量(点集);一个轮廓为vector<Point>,则contours可以为vector<vector<Point>>。
* @param hierarchy 可选的输出向量,包含图像的拓扑信息。其作为轮廓数量的表示包含了许多元素。每个轮廓 contours[i] 对应4个 hierarchy 元素 hierarchy[i][0]~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、内嵌轮廓、父轮廓的索引编号。如果没有对应项,对应值为负数。
* @param mode 轮廓检索模式,有 RETR_EXTERNAL, RETR_LIST, RETR_CCOMP, RETR_TREE
* @param method 轮廓的近似办法,有 CHAIN_APPROX_NONE, CHAIN_APPROX_SIMPLE, CHAIN_APPROX_TC89_L1, CHAIN_APPORX_TC89_KCOS
*/
void findContours(cv::InputArray image,
cv::OutputArrayOfArrays contours, //注意类型
cv::OutputArray hierarchy,
int mode, int method,
cv::Point offset = cv::Point())


绘制轮廓
void cv::drawContours(cv::InputOutputArray image,
cv::InputArrayOfArrays contours,
int contourIdx,
const cv::Scalar &color, int thickness = 1, int lineType = 8, cv::InputArray hierarchy = noArray(), int maxLevel = 2147483647, cv::Point offset = cv::Point())
/**
* @brief 通过findContours()得到的contours绘制轮廓
* @param image 目标图像
* @param contours 输入的轮廓
* @param contourIdx 指示要绘制的轮廓,即contours[i]。如果为负值,画出所有的轮廓
* @param color 轮廓的颜色
* @param thickness 轮廓线条的粗细,为负值会画在轮廓内部。默认值为1
*/
代码实例
Mat image=imread("/home/yunhua/Desktop/My_homework/2021.10.4-opencv-identify_sunflower/simple.png");
Mat dst;
Mat inRange_image;
Mat best_image;
Mat new1,new2,new3=image;
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(30,30));
//色彩通道转换
cvtColor(image,dst,COLOR_BGR2HSV);
imshow("HSV",dst);
inRange(dst,Scalar(0,163,243),Scalar(109,255,255),best_image);
erode(best_image,new1,element);
dilate(new1, new2, element);
//创建容器
vector<vector<Point>>coutours;
//寻找轮廓
findContours(new2,coutours,RETR_EXTERNAL,CHAIN_APPROX_NONE);
//绘制轮廓
drawContours(new3,coutours,-1,Scalar(0,0,255),1);
imshow("nice",new3);
waitKey(100000);
用几何图形拟合轮廓
/**
* @brief 用最小外包矩形拟合轮廓
* @param points 点集
* @return 返回一个RotatedRect对象,即旋转矩形
*/
cv::RotatedRect minAreaRect(cv::InputArray points)
/**
* @brief 用正矩形拟合轮廓
* @return 返回一个Rect对象,即正矩形
*/
cv::Rect boundingRect(cv::InputArray array)
/**
* @brief 用椭圆拟合轮廓
* @return 返回一个RotatedRect对象
*/
cv::RotatedRect fitEllipse(cv::InputArray points)
tips
- RotatedRect 和 Rect 不是同一个类,需要区分
- 虽然 OpenCV 没有直接提供椭圆的类,但我们依然可以通过RotatedRect 绘制椭圆
- 还有直线拟合、圆形拟合,可以自行查阅
绘制几何图形
/**
* @brief 在图像中画线段
* @param img 线段画在img上(下面的函数同理)
* @param pt1 端点1
* @param pt2 端点2
*/
void cv::line(cv::InputOutputArray img, cv::Point pt1, cv::Point pt2, const cv::Scalar &color, int thickness = 1, int lineType = 8, int shift = 0);
/**
* @brief 在图像中画正矩形
* @param rec 一个Rect对象,可以通过左上点和右下点构造一个Rect,Rect对象的其他构造方法自行查阅
*/
void cv::rectangle(cv::InputOutputArray img, cv::Rect rec, const cv::Scalar &color, int thickness = 1, int lineType = 8, int shift = 0);
/**
* @brief 在图像中画圆形
* @param center 圆心
* @param radius 半径
*/
void cv::circle(cv::InputOutputArray img, cv::Point center, int radius, const cv::Scalar &color, int thickness = 1, int lineType = 8, int shift = 0);
flip()函数 图像反转
cv::Mat image=imread("");
cv::Mat result; //创建一个空的图像
cv::flip(image,result,1);//正数表示水平,0表示垂直,负数表示水平和垂直