opencv_c++学习(下)(图片裁剪,投影,颜色识别,形状识别)
在img上输入文案,文案是“6666666666”,初始点是矩形左上角(137,262),FONT_HERSHEY_COMPLEX表示字体,右很多种字体,可以自行查阅,大小是0.75,颜色是黑(0,0,0),粗细是1。在img上作矩形,两个点可以确定矩形,分别是左上角和右下角两点,颜色是白(255,255,255),FILLED表示填满(也可以是其他数字,与圆最后一个参数同样,表示线的粗度)在im
一.图片裁剪与选取部分
int main()
{
string path = "C:\\Users\\jishu\\Pictures\\aoqi";//这里的路径是你图片的绝对路径,并且用\\来分隔每个文件
Mat img = imread(path);
Mat imgResize, imgGrop;
resize(img, imgResize, Size(), 0.5, 0.5);
Rect roi(27, 54, 162, 209);
imgGrop = img(roi);
imshow("img", img);
imshow("img Reasize", imgResize);
imshow("img Grop", imgGrop);
waitKey(0);
return 0;
}
resize:作用是调整图片大小,可以在size中填入你想要的大小,也可以在第四五位参数用倍数调整。
选取部分图片
先建立一个矩形roi,里面的参数分别是矩形左上角的xy像素点坐表和右下角xy的像素点坐标
在画图工具中打开图片,选取图中白色精灵圈出的小点,坐标位置在左下角。

代码效果如下

二.建立图形(矩形,圆形,线等)
int main()
{
Mat img(512, 512, CV_8UC3, Scalar(255,255,0));
circle(img, Point(256, 256), 155, Scalar(0, 0, 0), 5);
rectangle(img, Point(130,226), Point(382,296), Scalar(255,255,255), FILLED);
line(img, Point(130,296), Point(382,296), Scalar(0,0,0), 3);
putText(img, "666666666666", Point(137,262), FONT_HERSHEY_COMPLEX,0.75, Scalar(0,0,0), 1);
imshow("image", img);
waitKey(0);
return 0;
}
Mat img(512, 512, CV_8UC3, Scalar(255,255,0));
创建一个名为img的Mat变量,给这个变量长宽各512,512(前两个参数)的像素,一个颜色由三种(C3)通道组成,一个通道有8个bit位(8U)组成,255种情况,颜色组成是Red+Green(255,255,0)。
circle(img, Point(256, 256), 155, Scalar(0, 0, 0), 5);
在img上作圆,原点坐标是Point(256,256),半径是155,颜色是黑(0,0,0),线粗度是5
rectangle(img, Point(130,226), Point(382,296), Scalar(255,255,255), FILLED);
在img上作矩形,两个点可以确定矩形,分别是左上角和右下角两点,颜色是白(255,255,255),FILLED表示填满(也可以是其他数字,与圆最后一个参数同样,表示线的粗度)
line(img, Point(130,296), Point(382,296), Scalar(0,0,0), 3);
在img上作线,两点(Point)确定一线,颜色是黑(0,0,0).粗度是3
putText(img, "666666666666", Point(137,262), FONT_HERSHEY_COMPLEX,0.75, Scalar(0,0,0), 1);
在img上输入文案,文案是“6666666666”,初始点是矩形左上角(137,262),FONT_HERSHEY_COMPLEX表示字体,右很多种字体,可以自行查阅,大小是0.75,颜色是黑(0,0,0),粗细是1
效果图

三.图片投影
int main()
{
float w = 250, h = 350;
Mat matrix, imgWarp;
string path = "Resources/cards.jpg";
Mat img = imread(path);
Point2f src[4] = { {528,144}, {772,192}, {403,393}, {674,457} };
Point2f dis[4] = { {0.0f,0.0f},{w,0.0f},{0.0f,h},{w,h} };
/*for (int i =0; i < 4; i++) {
circle(img, Point(src[i]), 2, Scalar(0, 0, 0), FILLED);
}*/
matrix = getPerspectiveTransform(src, dis);
warpPerspective(img, imgWarp, matrix, Point(w, h));
imshow("Image", img);
imshow("Img Warp", imgWarp);
waitKey(0);
return 0;
}
便于理解先发效果图了(这里选取扑克k)

point2f表示point表示点,2表示一个点由两个属性组成,f表示数的精度。
注释的代码是确定找的点概括到了扑克牌四个点
w,h是提前计算好的扑克牌的宽和高
matrix = getPerspectiveTransform(src, dis);
warpPerspective(img, imgWarp, matrix, Point(w, h));
为代码的核心函数,可以把src中斜着的图像拉正
四.颜色识别
要先讲rgb图像转成hsv图像,在特定的h,s,v的范围内(指的其实就是某种颜色的相近范围),对应的颜色会在黑色图像同样生成白色掩膜
首先,我们需要回忆起hsv图像(很重要,不懂的可以去看上一章内容)
int main()
{
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);
namedWindow("Trackbars",(640,200));
createTrackbar("Hue Min", "Trackbars", &hmin, 179);
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)
{
Scalar lower(hmin, smin,vmin);
Scalar upper(hmax, smax, vmax);
inRange(imgHSV, lower, upper, mask);
imshow("Image", img);
imshow("Image HSV", imgHSV);
imshow("MASK", mask);
waitKey(1);
}
return 0;
}
cvtColor(img, imgHSV, COLOR_BGR2HSV);
讲原来的图像转为hsv图像
Scalar lower(hmin, smin,vmin);
Scalar upper(hmax, smax, vmax);
分别生成lower和upper两种颜色(Scalar表示声明创建的变量的是颜色)
展示一下效果,方便理解

int hmin=0, smin=110, vmin=153;
int hmax=19, smax=240, vmax=255;
表示检测的是图中汽车车身的颜色,是一个范围
namedWindow("Trackbars",(640,200));
createTrackbar("Hue Min", "Trackbars", &hmin, 179);
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);
创建名为"Trackbars"的一个窗口,大小是(640,200)
createTrackbar表示在第二个参数"Trackbars"的窗口生成一个名为"Hue Min"轨道条,拖动轨道可以改变&hmin这个地址中的值(以第一个举列)
五.轮廓检测
void getContours(Mat imgDil, Mat img)
{
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
vector<vector<Point>> conPoly(contours.size());
vector<Rect> boundRect(contours.size());
for (int i = 0; i < contours.size(); i++)
{
string objectType;
int area = contourArea(contours[i]);
cout << area << endl;
if (area > 1000)
{
float peri = arcLength(contours[i], true);
approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);
cout << conPoly[i].size() << endl;
//drawContours(img, contours, -1, Scalar(255, 0, 255), 2);
boundRect[i] = boundingRect(conPoly[i]);
int objCor = (int)conPoly[i].size();
if (objCor == 3)
{
objectType = "Tri";
}
else if (objCor == 4)
{
float aspRatio = (float)boundRect[i].width / (float)boundRect[i].height;
if (aspRatio <= 1.05 && aspRatio >= 0.95)
{
objectType = "Square";
}
else {
objectType = "Rect";
}
}
else if (objCor > 4)
{
objectType = "Circle";
}
drawContours(img, conPoly, i, Scalar(255, 0, 255), 2);
rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(255,0,255), 2);
putText(img, objectType, { boundRect[i].x, boundRect[i].y-5 }, FONT_HERSHEY_COMPLEX,
0.5, Scalar(0,0,0), 1);
}
}
}
int main()
{
string path = "Resources/shapes.png";//这里的路径是你图片的绝对路径,并且用\\来分隔每个文件
Mat img = imread(path);
Mat imgGray, imgBlur, imgCanny, imgDil, imgEro;
cvtColor(img, imgGray, COLOR_BGR2GRAY);
GaussianBlur(img, imgBlur, Size(3, 3), 3, 0);
Canny(imgBlur, imgCanny, 25, 75);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
dilate(imgCanny, imgDil, kernel);
erode(imgDil, imgEro , kernel);//预处理
getContours(imgDil, img);
imshow("Image Dil", imgDil);
imshow("Image", img);
waitKey(0);
return 0;
}
cvtColor(img, imgGray, COLOR_BGR2GRAY);
GaussianBlur(img, imgBlur, Size(3, 3), 3, 0);
Canny(imgBlur, imgCanny, 25, 75);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
dilate(imgCanny, imgDil, kernel);
erode(imgDil, imgEro , kernel);//预处理
对图像进行预处理,转化为描边的二值图像
接下来重点,讲解核心自定义函数getContours(Mat imgDil, Mat img),看不懂的可以先跟着我下面的理解一步一步看
参数分别是描边二值图像和原图像
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
查找Dil图像中的形状,具体怎么用可以ai一下这里
vector<vector<Point>> contours如何理解这串代码
先看里面vector<Point>,表示点的数组,数组中的每一个元素代表一个点,一个数组包含数个点,可以理解为是一个轮廓
再看vector<vector<Point>>,以轮廓(以点为单位的数组)为单位,建立一个数组,数组里数个轮廓组成。
vector<Vec4i> hierarchy;
存储轮廓关系的一个数组,可以理解是轮廓之间的父子关系(哪个轮廓在哪个里面)
for (int i = 0; i < contours.size(); i++)
{
}
这个for循环表示阅历每一个轮廓
int area = contourArea(contours[i]);
cout << area << endl;
if (area > 1000)
计算每个轮廓占的面积,并过滤掉噪音
vector<vector<Point>> conPoly(contours.size());
表示再建立一个只包含多边形的数组,目的是之后要把圆转为多边形,以便分辨图形(圆没有明显的识别特征,转化成多边形,特征便是多个端点)
vector<Rect> boundRect(contours.size());
这个数组内是boundingRect输出的结果(矩形的数据(x, y, width, height))
float peri = arcLength(contours[i], true);
approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);
先计算轮廓的周长peri,用 approxPolyDP把轮廓像多边形逼近,如把圆逼近至八边形。
int objCor = (int)conPoly[i].size();
if (objCor == 3)
{
objectType = "Tri";
}
else if (objCor == 4)
{
float aspRatio = (float)boundRect[i].width / (float)boundRect[i].height;
if (aspRatio <= 1.05 && aspRatio >= 0.95)
{
objectType = "Square";
}
else {
objectType = "Rect";
}
}
else if (objCor > 4)
{
objectType = "Circle";
}
识别各种形状
drawContours(img, conPoly, i, Scalar(255, 0, 255), 2);
将轮廓逼近多边形后的轮廓在img图上用紫色画出来
rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(255,0,255), 2);
将轮廓中的点以一个最小面积的矩形围住
putText(img, objectType, { boundRect[i].x, boundRect[i].y-5 }, FONT_HERSHEY_COMPLEX,
0.5, Scalar(0,0,0), 1);
在对应位置写出轮廓的形状
下面展示代码效果

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)