# opencv处理图像 **Repository Path**: thesecret/opencv-image-processing ## Basic Information - **Project Name**: opencv处理图像 - **Description**: opencv处理图像 - **Primary Language**: C++ - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 6 - **Forks**: 1 - **Created**: 2022-03-20 - **Last Updated**: 2025-01-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # opencv处理图像 ## 要求 描述:实现一个基本流水线过程,并考虑图片不均情况下处理 \ 知识点:buffer,泊松过程, opencv,数据拷贝,内存管理 ## 思路 1.单进程与多线程批量读取图片,模拟读取图片不均的过程 \ 2.对比时间 ### 实现功能 ![Image text](https://gitee.com/thesecret/opencv-image-processing/raw/master/res.png) ## opencv基本用法 ### 读取图像 ```cpp #include #include #include #include using namespace std; using namespace cv; void main() { string path = "resources/test.png"; Mat img = imread(path); imshow("test", img); waitKey(0); //增加延时,0表示无穷 } ``` ### 读取视频 ```cpp #include #include #include #include using namespace std; using namespace cv; void main() { string path = "Resources/test_video.mp4"; VideoCapture cap(path); Mat img; while (true) { cap.read(img); imshow("Image", img); waitKey(20); //增加延时 20ms } } ``` ### 读取摄像头 ```cpp #include #include #include #include using namespace std; using namespace cv; void main() { VideoCapture cap(0); //相机id=0 Mat img; while (true) { cap.read(img); imshow("Image", img); waitKey(1); //增加延时 1ms,以免太慢 } } ``` ### 图像处理(灰度、高斯模糊、边缘检测、扩张边缘、侵蚀边缘) ```cpp #include #include #include #include using namespace std; using namespace cv; void main() { string path = "Resources/test.png"; Mat img=imread(path); Mat imgGray,imgBlur,imgCanny,imgDil,imgErode; cvtColor(img, imgGray, COLOR_BGR2GRAY);//cvt是convert的缩写,将图像从一种颜色空间转换为另一种颜色空间。 GaussianBlur(imgGray, imgBlur,Size(7,7),5,0);//使用高斯滤波器模糊图像。该函数将源图像与指定的高斯核进行卷积,Size(7,7)是核大小,数字越大越模糊 Canny(imgBlur, imgCanny, 25, 75);//边缘检测,阈值1,2可调,目的:显示更多的边缘 Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));//创建一个核,增加Size(只能是奇数)会扩张/侵蚀更多 dilate(imgCanny, imgDil, kernel);//扩张边缘(增加边缘厚度) erode(imgDil, imgErode, kernel);//侵蚀边缘(减小边缘厚度) imshow("Image", img); imshow("Image Gray", imgGray); imshow("Image Blur", imgBlur); imshow("Image Canny", imgCanny); imshow("Image Dilation", imgDil); imshow("Image Erode", imgErode); waitKey(0); } ``` ### 学习如何调整大小以及裁剪图像 ```cpp #include #include #include #include using namespace std; using namespace cv; void main() { string path = "Resources/test.png"; Mat img=imread(path);//matrix data type 由opencv引入来处理图像 Mat imgResize,imgCrop; cout << img.size() << endl;//打印图像尺寸 resize(img, imgResize, Size(640, 480));//指定图片尺寸缩放 //resize(img, imgResize, Size(),0.5,0.5);//指定缩放比例,不指定图片尺寸 //矩形数据类型 Rect roi(200, 100, 300, 300);//以左上角为坐标原点,(200,100)为矩形的左上角坐标,300,300为矩形长宽 imgCrop = img(roi);//裁剪图像,为了找到特定区域 添加更多处理 roi:region of interest imshow("Image", img); imshow("Image Resize", imgResize); imshow("Image Crop", imgCrop); waitKey(0);//增加延时,0表示无穷 } ``` ### 学习如何绘制形状(圆形、矩形、线段)和如何在图片上写字 ```cpp #include #include #include #include using namespace std; using namespace cv; void main() { //创建空白图像 //Scalar(255, 0, 255),(蓝色:255,0,0),(紫色:255,0,255),(黑色:0,0,0),(白色:255,255,255) Mat img(512, 512, CV_8UC3, Scalar(255, 255, 255));//(512,512)为图片大小,CV8UC3中8表示每个像素的值从0到255,3表示3个颜色通道BGR,Scalar(255, 0, 0)表示图像将具有的颜色 circle(img, Point(256, 256), 155,Scalar(0,69,255),FILLED);//第一个参数:图片,第二个参数是圆心坐标,第三个参数是圆大小,第四个参数是颜色,第五个参数是厚度(可以不写),想要填充可以填FILLED rectangle(img, Point(130,226), Point(382,286),Scalar(255,255,255),FILLED);//第一个Point给矩形左上角坐标,第二个Point给矩形右下角坐标 line(img, Point(130, 296), Point(382, 296), Scalar(255, 255, 255), 2);//第一个Point是起点坐标、第二个Point是终点坐标 putText(img, "hello world!", Point(137, 262), FONT_HERSHEY_DUPLEX, 0.75, Scalar(0, 69, 255), 2); imshow("Image", img); waitKey(0);//增加延时,0表示无穷 } ``` ### 学习如何扭曲图像、提取图像 ```cpp #include #include #include #include using namespace std; using namespace cv; float w = 250, h = 350;//图片大小 Mat matrix, imgWarp; void main() { //图片用画图打开,在屏幕左下角会显示点的坐标 string path = "Resources/cards.jpg"; Mat img=imread(path); Point2f src[4] = { {529,142},{771,190},{405,395},{674,457} };//Point2f表示浮点数 Point2f dst[4] = { {0.0f,0.0f},{w,0.0f},{0.0f,h},{w,h} };//Point2f表示浮点数 matrix = getPerspectiveTransform(src, dst); warpPerspective(img, imgWarp, matrix, Point(w,h)); //确定src坐标是否正确(画圆点) for (int i = 0; i < 4; i++) { circle(img, src[i], 10, Scalar(0, 0, 255), FILLED); } imshow("Image", img); imshow("Image Warp", imgWarp); waitKey(0);//增加延时,0表示无穷 } ``` ### 学习检测图片中的颜色,来创建特定对象的对象检测器 ```cpp #include #include #include #include using namespace std; using namespace cv; int hmin = 0, smin = 0, vmin = 0; int hmax = 179, smax = 255, vmax = 255;//如何确定这6个值,每次都更改所有这些再次运行很痛苦 -->创建跟踪栏(使我们可以实时更改这些值) void main() { string path = "Resources/shapes.png"; Mat img=imread(path); Mat imgHSV,mask; cvtColor(img, imgHSV, COLOR_BGR2HSV);//转换图像到HSV空间,在其中查找颜色更加容易 namedWindow("Trackbars", (640, 200));//(640,200)是尺寸 //运行时,把3个min的都移到最小值,把3个max的都移到最大值,然后移动使其保持为白色 createTrackbar("Hue Min", "Trackbars", &hmin, 179);//对于hue色相饱和度最大180,对于另外两个色相饱和度最大255 createTrackbar("Hue Max", "Trackbars", &hmax, 179); createTrackbar("Sat Min", "Trackbars", &smin, 255); createTrackbar("Sat Max", "Trackbars", &smax, 255); createTrackbar("Val Min", "Trackbars", &vmin, 255); createTrackbar("Val Max", "Trackbars", &vmax, 255); while (true) { //检查数组元素是否位于其他两个数组的元素之间。 //imgHSV为输入图像,mask为输出图像 Scalar lower(hmin, smin, vmin); Scalar upper(hmax, smax, vmax); inRange(imgHSV, lower, upper, mask);//定义颜色下限和上限,因为由于照明和不同的阴影,颜色的值将不完全相同,会是一个值的范围 imshow("Image", img); imshow("Image HSV", imgHSV); imshow("Image mask", mask); waitKey(1);//增加延时 } } ``` ### 学习如何检测形状或图像中的轮廓 ```cpp /* 描绘图像形状 */ #include #include #include #include using namespace std; using namespace cv; //! 获取轮廓 void getContours(Mat imgDil, Mat img) {//imgDil是传入的扩张边缘的图像用来查找轮廓,img是要在其上绘制轮廓的图像 vector> contours;//轮廓检测到的轮廓。每个轮廓线存储为一个点的向量 vector hierarchy;//包含关于映像拓扑的信息 typedef Vec Vec4i;具有4个整数值 //在二值图像中查找轮廓。该函数利用该算法从二值图像中提取轮廓 findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); //img:要绘制轮廓在什么图片上,contours:要绘制的轮廓,-1定义要绘制的轮廓号(-1表示所有轮廓),Saclar表示轮廓颜色,2表示厚度 drawContours(img, contours, -1, Scalar(255, 0, 255), 2); } void main() { string path = "Resources/shapes.png"; Mat img=imread(path); //在检测形状前,对图片预处理:转换为灰度、添加高斯模糊、使用Canny边缘检测器、扩张边缘 Mat imgGray, imgBlur, imgCanny, imgDil, imgErode; cvtColor(img, imgGray, COLOR_BGR2GRAY);//cvt是convert的缩写,将图像从一种颜色空间转换为另一种颜色空间。 GaussianBlur(imgGray, imgBlur,Size(3,3),3,0);//使用高斯滤波器模糊图像。该函数将源图像与指定的高斯核进行卷积,Size(7,7)是核大小,数字越大越模糊 Canny(imgBlur, imgCanny, 25, 75);//边缘检测,阈值1,2可调,目的:显示更多的边缘 Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));//创建一个核,增加Size(只能是奇数)会扩张/侵蚀更多 dilate(imgCanny, imgDil, kernel);//扩张边缘(增加边缘厚度) getContours(imgDil,img);//img是在其上绘轮廓的图片 imshow("Image", img); /*imshow("Image Gray", imgGray); imshow("Image Blur", imgBlur); imshow("Image Canny", imgCanny); imshow("Image Dil", imgDil);*/ waitKey(0);//增加延时,0表示无穷 } ``` ```cpp //! 过滤器 #include #include #include #include using namespace std; using namespace cv; //! 获取轮廓 void getContours(Mat imgDil, Mat img) {//imgDil是传入的扩张边缘的图像用来查找轮廓,img是要在其上绘制轮廓的图像 vector> contours;//轮廓检测到的轮廓。每个轮廓线存储为一个点的向量 vector hierarchy;//包含关于映像拓扑的信息 typedef Vec Vec4i;具有4个整数值 //在二值图像中查找轮廓。该函数利用该算法从二值图像中提取轮廓 findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); //img:要绘制轮廓在什么图片上,contours:要绘制的轮廓,-1定义要绘制的轮廓号(-1表示所有轮廓),Saclar表示轮廓颜色,2表示厚度 //drawContours(img, contours, -1, Scalar(255, 0, 255), 2); vector> conPoly(contours.size());//conploy的数量应小于contours vector boundRect(contours.size()); ////过滤器:通过轮廓面积来过滤噪声 for (int i = 0; i < contours.size(); i++) {//遍历检测到的轮廓 int area = contourArea(contours[i]); cout << area << endl; string objectType; if (area > 1000) {//轮廓面积>1000才绘制 //计算轮廓周长或凹坑长度。该函数计算了曲线长度和封闭的周长。 float peri = arcLength(contours[i], true);//计算封闭轮廓周长 approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);//以指定的精度近似多边形曲线。第二个参数conPloy[i]存储近似的结果,是输出。 boundRect[i] = boundingRect(conPoly[i]);//计算边界矩形 int objCor = (int)conPoly[i].size();//找近似多边形的角点,三角形有3个角点,矩形/正方形有4个角点,圆形>4个角点 cout << objCor << endl; if (objCor == 3) { objectType = "Tri"; } else if (objCor == 4) { float aspRatio = (float)boundRect[i].width / (float)boundRect[i].height;//宽高比 if (aspRatio > 0.95 && aspRatio < 1.05) { objectType = "Square"; }//矩形的宽高比不会正好等于1 else objectType = "Rect"; } else if (objCor > 4) { objectType = "Circle"; } drawContours(img, conPoly, i, Scalar(255, 0, 255), 2); /*tl():topleft矩形左上角坐标*/ /*br():bottom right矩形右下角坐标*/ rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 5); /*文字坐标*/ putText(img, objectType, { boundRect[i].x,boundRect[i].y - 5 }, FONT_HERSHEY_PLAIN, 1, Scalar(0, 69, 255), 2); } } } void main() { string path = "Resources/shapes.png"; Mat img=imread(path); //在检测形状前,对图片预处理:转换为灰度、添加高斯模糊、使用Canny边缘检测器、扩张边缘 Mat imgGray, imgBlur, imgCanny, imgDil, imgErode; cvtColor(img, imgGray, COLOR_BGR2GRAY);//cvt是convert的缩写,将图像从一种颜色空间转换为另一种颜色空间。 GaussianBlur(imgGray, imgBlur,Size(3,3),3,0);//使用高斯滤波器模糊图像。该函数将源图像与指定的高斯核进行卷积,Size(7,7)是核大小,数字越大越模糊 Canny(imgBlur, imgCanny, 25, 75);//边缘检测,阈值1,2可调,目的:显示更多的边缘 Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));//创建一个核,增加Size(只能是奇数)会扩张/侵蚀更多 dilate(imgCanny, imgDil, kernel);//扩张边缘(增加边缘厚度) getContours(imgDil,img);//img是在其上绘轮廓的图片 imshow("Image", img); /*imshow("Image Gray", imgGray); imshow("Image Blur", imgBlur); imshow("Image Canny", imgCanny); imshow("Image Dil", imgDil);*/ waitKey(0);//增加延时,0表示无穷 } ``` ### 学习检测图像中的面部 ```cpp #include #include #include #include//对象检测头文件 #include using namespace std; using namespace cv; void main() { string path = "Resources/test.png"; Mat img=imread(path); /*用于对象检测的级联分类器类*/ CascadeClassifier faceCascade; //从文件加载分类器(已经训练好的模型) faceCascade.load("Resources/haarcascade_frontalface_default.xml"); if (faceCascade.empty()) { cout << "XML file not loaded" << endl; }//检测文件是否加载成功 vector faces; /*输入*输出*比例因子*最小邻居*/ //在输入图像中检测不同大小的对象。检测到的对象将以矩形列表的形式返回。 faceCascade.detectMultiScale(img, faces, 1.1, 10); for (int i = 0; i < faces.size(); i++) { rectangle(img, faces[i].tl(),faces[i].br(), Scalar(255, 0, 255), 3);//绘制矩形 } imshow("Image", img); waitKey(0);//增加延时,0表示无穷 } ```