首页 >> 大全

**考核任务总结 ——基于opencv的形状识别任务总结

2023-12-11 大全 26 作者:考证青年

**考核任务总结 ——基于的形状识别任务总结 前言

​ 在的初学之旅中,我深感这个图像处理库的简洁和灵活性,使我能够迅速上手,享受编写高效 图像处理代码的乐趣。其强大功能从基本的图像操作到复杂的计算机视觉任务无所不包,让我逐渐理解 了图像处理的核心概念,并能够熟练运用各种处理技术。开源的特性为我提供了丰富的学习资源,与庞大的开源社区互动让我受益匪浅。通过实践编写代码,我深刻体会到理论知识的实际应用,而 提供的示例代码和文档以及为我的实践提供了坚实的基础。

一、主要设计思路 通过摄像头或选择图像文件的方式获取输入图像。对输入图像进行初步处理,包括颜色空间转换、滤波、边缘检测等操作,得到处理后的图像。使用轮廓检测函数来获取图像中的轮廓。对每个轮廓进行处理和分析,包括计算面积、周长、圆度等属性,并通过拟合多边形和凸包检测来判断形状类型。根据形状类型进行相应的处理,如绘制轮廓、截取形状、检测颜色等。在图像上标注形状名称和颜色信息,并显示处理后的图像。 二、技术要点和代码实现 1.导入头文件等基本操作

#include 
#include 
#include using namespace cv;
using namespace std;

2.函数定义 (1)定义列表

//打开文件模块头文件
string openFile(const wchar_t* windowTitle){}

//临边长比过滤函数【多边形approx,多边形边数,临边比上限,临边比下限】
bool SLengthDetect(vectorapprox, int sides, double RatioUpper, double RatioLower){}

//图形颜色判断函数【返回形状名称】
string judgeColor(int hue){}

//颜色检测并标注的函数(需要标注的图像,标注基准点,滤波图)【返回图形hue值】
int detectColor(Mat imgRead, Point center, Mat midblurcolor){}

//截取形状图片函数 (形状的轮廓,传入图像,形状名称,编号)
void CatchShape(vector approx, Mat imageRead, string shape, int id){}

//非摄像机图像初步处理函数
Mat ProcessImg(Mat imgRead){}

//摄像机图像初步处理函数
Mat CamProcessingImg(Mat img)

//形状识别相关函数(传入图像,是否截取形状,是否复刻原图,是否检测颜色,是否进入摄像机模式)
int reconizeShape(Mat imgRead, bool is_CATCHSHAPE, bool is_COPY, bool is_DETECTCOLOR, bool is_CameraMode){}

(2)函数具体定义

//打开文件模块头文件
string openFile(const wchar_t* windowTitle)
{OPENFILENAME ofn;wchar_t szFile[260] = { 0 };ZeroMemory(&ofn, sizeof(ofn));ofn.lStructSize = sizeof(ofn);ofn.lpstrFile = szFile;ofn.nMaxFile = sizeof(szFile);ofn.lpstrTitle = windowTitle; // 使用传入的窗口名称ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST;ofn.lpstrFilter = L"Image Files\0*.bmp;*.jpg;*.png;*.JPEG;*.JPE;\0";if (!GetOpenFileName(&ofn))
{wcout << L"没有选择到文件。" << endl;return "";
}int size = WideCharToMultiByte(CP_UTF8, 0, ofn.lpstrFile, -1, nullptr, 0, nullptr, nullptr);
std::string selectedFile(size, 0);
WideCharToMultiByte(CP_UTF8, 0, ofn.lpstrFile, -1, &selectedFile[0], size, nullptr, nullptr);return selectedFile;}//临边长比过滤函数【多边形approx,多边形边数,临边比上限,临边比下限】
bool SLengthDetect(vectorapprox, int sides, double RatioUpper, double RatioLower)
{bool valid_shape = true;vector edge_lengths;for (size_t i = 0; i < sides; i++) {Point v = approx[i] - approx[(i + 1) % sides];double length = norm(v);edge_lengths.push_back(length);}for (size_t i = 0; i < sides; i++) {double ratio = edge_lengths[i] / edge_lengths[(i + 1) % sides];if (ratio < RatioLower || ratio > RatioUpper) {valid_shape = false;break;}
}return valid_shape;}//图形颜色判断函数【返回形状名称】
string judgeColor(int hue)
{// 判断红色
if ((hue >= 0 && hue <= 15))
{return "Red";
}// 判断橙色
if (hue > 15 && hue <= 20)
{return "Orange";
}// 判断黄色
if (hue > 20 && hue <= 45)
{return "Yellow";
}// 判断绿色
if (hue > 45 && hue <= 90)
{return "Green";
}// 判断蓝色
if (hue > 90 && hue <= 115)
{return "Blue";
}// 判断紫色
if (hue > 115 && hue <= 175)
{return "Purple";
}return "Unknown color";}//颜色检测并标注的函数(需要标注的图像,标注基准点,滤波图)【返回图形hue值】
int detectColor(Mat imgRead, Point center, Mat midblurcolor)
{//检测中心点颜色Rect regionOfInterest((center.x) - 5, (center.y) - 5, 10, 10); //取样Mat roi = midblurcolor(regionOfInterest);// 创建一个副本,仅包含指定区域的图像数据int totalHue = 0;
int pixelCount = 0;  // 初始化Hue总和和像素计数器// 遍历区域内的每个像素并计算Hue总和
for (int y = 0; y < roi.rows; y++) {for (int x = 0; x < roi.cols; x++) {Vec3b pixel = roi.at(y, x);Mat3b rgb(pixel);Mat3b hsv;cvtColor(rgb, hsv, COLOR_BGR2HSV);int hue = hsv(0, 0)[0];totalHue += hue;pixelCount++;}
}// 计算Hue的平均值
int averageHue = totalHue / pixelCount;string centerColor = judgeColor(averageHue);
Point olcenter(center.x, center.y + 30);
putText(imgRead, centerColor, olcenter, FONT_HERSHEY_SIMPLEX, 0.6, Scalar(0, 0, 255), 1);return averageHue;}//截取形状图片函数 (形状的轮廓,传入图像,形状名称,编号)
void CatchShape(vector approx, Mat imageRead, string shape, int id)
{//分别截取形状Rect boundingBox = boundingRect(approx);Mat CatC = imageRead(boundingBox);bool saved = imwrite(shape + to_string(id) + ".jpg", CatC, { IMWRITE_JPEG_QUALITY, 90 });}//摄像机图像初步处理函数
Mat CamProcessingImg(Mat img)
{// 转换为HSV颜色空间Mat HSV;cvtColor(img, HSV, COLOR_BGR2HSV);// 定义白色的饱和度阈值
Scalar lower(0, 35, 0);
Scalar upper(179, 255, 255);// 创建一个掩码来过滤背景
Mat mask;
inRange(HSV, lower, upper, mask);// 高斯模糊
Mat blur;
GaussianBlur(mask, blur, Size(5, 5), 1);// 使用Canny算子提取边缘
Mat canny;
Canny(blur, canny, 50, 50);// 一次闭运算,去除杂点
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
Mat mask1;
Mat mask2;
dilate(canny, mask1, kernel, Point(-1, -1), 1);
erode(mask1, mask2, kernel, Point(-1, -1), 1);return mask2;}//非摄像机图像初步处理函数
Mat ProcessImg(Mat imgRead)
{// 灰度图像转换 Mat gray;cvtColor(imgRead, gray, COLOR_BGR2GRAY);// 中值滤波
Mat midblurgray;
medianBlur(gray, midblurgray, 5);// 执行高斯滤波
Size kernelSize(5, 5);
Mat gaussgray;
GaussianBlur(midblurgray, gaussgray, kernelSize, 2.5, 2.5);//二值化处理
Mat binary;
threshold(gaussgray, binary, 150, 250, THRESH_BINARY_INV);// 边缘检测
Mat cannygray;
Canny(binary, cannygray, 100, 150);return cannygray;}

//形状识别相关函数(传入图像,是否截取形状,是否复刻原图,是否检测颜色,是否进入摄像机模式)
int reconizeShape(Mat imgRead, bool is_CATCHSHAPE, bool is_COPY, bool is_DETECTCOLOR, bool is_CameraMode)
{// 定义颜色Scalar Rcolor(0, 0, 255); // 红色//新建复刻用画布
Mat whiteimg(imgRead.size(), CV_8UC3, Scalar(255, 255, 255));//错误处理
if (imgRead.empty()) {cerr << "Error: Could not load imgRead." << endl;return -1;
}// 中值滤波(用于检测颜色)
Mat midblurcolor;
medianBlur(imgRead, midblurcolor, 15);//图像初步处理
Mat cannygray;
if (!is_CameraMode) { cannygray = ProcessImg(imgRead); }
else { cannygray = CamProcessingImg(imgRead); }// 读取轮廓
vector> contours;
if(is_CameraMode){ findContours(cannygray, contours, RETR_LIST, CHAIN_APPROX_SIMPLE); }
else { findContours(cannygray, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); }// 历遍每个轮廓
for (size_t i = 0; i < contours.size(); ++i)
{//-------轮廓相关信息采集与初步过滤---------//double area = contourArea(contours[i]); // 计算面积if (area < 300) { continue; } //过滤掉面积过小的轮廓double perimeter = arcLength(contours[i], true); // 计算周长double circularity = 4 * CV_PI * area / (perimeter * perimeter); // 计算圆度// 设置一个阈值来筛选陡峭的边
if (circularity < 0.2) { continue; }
//--------------------------------//// 二次拟合多边形
vector approx1;
vector approx2;
approxPolyDP(contours[i], approx1, 0.001 * arcLength(contours[i], true), true);
approxPolyDP(approx1, approx2, 0.03 * arcLength(contours[i], true), true);// 获取多边形的顶点数
int numVertices = approx2.size();//  计算轮廓的中心
Moments M = moments(contours[i]);
Point center(int(M.m10 / M.m00), int(M.m01 / M.m00));// -----根据顶点数和凸包数最后一步过滤并判断形状-------//
int numSides = approx2.size();
string shape;if (numSides == 3)
{vector Tcontours;convexHull(approx2, Tcontours);//凸包检测if (Tcontours.size() == 3 && SLengthDetect(approx2, 3, 10, 0.1)){shape = "Triangle";drawContours(imgRead, contours, i, Rcolor, 1);}
}
else if (numSides == 4)
{​    vector Rcontours;
​    convexHull(approx2, Rcontours);
​    if (Rcontours.size() == 4 && SLengthDetect(approx2, 4, 1.5, 0.6))
​    {            shape = "Rectangle";
​        drawContours(imgRead, contours, i, Rcolor, 1);
​    }
}
else if (numSides == 5)
{​    vector Pgcontours;
​    convexHull(approx2, Pgcontours);
​    if (Pgcontours.size() == 5 && SLengthDetect(approx2, 5, 2.5, 0.4))
​    {
​        shape = "Pentagon";
​        drawContours(imgRead, contours, i, Rcolor, 1);
​    }
}
else if (numSides == 6)
{​    vector Pccontours;        convexHull(approx2, Pccontours);
​    if (Pccontours.size() == 6 && SLengthDetect(approx2, 6, 2.5, 0.4))
​    {
​        shape = "Hexagon";
​        drawContours(imgRead, contours, i, Rcolor, 1);
​    }
}
else if (numSides == 10)
{
​    vector Pccontours;
​    convexHull(approx2, Pccontours);
​    if (Pccontours.size() == 5)
​    {
​        shape = "Pentacle";
​       drawContours(imgRead, contours, i, Rcolor, 1);
​    }}
else if (numSides > 7)
{// 圆形的检测float peri1 = arcLength(contours[i], true);float apm = (peri1 * peri1) / (area * 4);if (apm > 2.4 && apm < 3.8){shape = "Circle";drawContours(imgRead, contours, i, Rcolor, 1);}
}
else { continue; }
//----------------------------////截取形状if (is_CATCHSHAPE){CatchShape(approx2, imgRead, shape, i);}//  检测颜色并标注
int averageHue = 0;
if (is_DETECTCOLOR)
{averageHue = detectColor(imgRead, center, midblurcolor);
}//hue平均值转BGR
Mat hsvColor(1, 1, CV_8UC3, Scalar(averageHue, 255, 255));
Mat rgbColor;cvtColor(hsvColor, rgbColor, COLOR_HSV2BGR);// 提取BGR颜色值Vec3b rgbPixel = rgbColor.at(0, 0);int eblue = rgbPixel[0];int egreen = rgbPixel[1];int ered = rgbPixel[2];//复刻图片中的形状
if (is_COPY)
{drawContours(whiteimg, contours, i, Scalar(eblue, egreen, ered), -1);
}//标注形状名称,画出轮廓putText(imgRead, shape, center, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0), 1);
}if (is_COPY)
{imshow("copyimg", whiteimg);
}return 0;}

int main()
{int mode = 0;do{cout << "请输入对应模式的数字\n1.摄像机模式\n2.图像模式" << endl;cin >> mode;if (mode == 1){VideoCapture cap(1);if (!cap.isOpened()){cerr << "Error: Couldn't open the camera." << endl;return -1;}int frameCount = 0;auto start = chrono::high_resolution_clock::now();while (true){// 使用shared_ptr创建Mat对象,确保自动内存管理shared_ptr frame = make_shared();// 从摄像头中读取帧cap >> *frame;if (frame->empty()){cerr << "Error: Couldn't read a frame from the camera." << endl;break;}// 进行帧处理操作reconizeShape(*frame, 0, 0, 1, 1);// 计数帧frameCount++;// 计时法估算帧率auto end = chrono::high_resolution_clock::now();double elapsedTime = chrono::duration_cast(end - start).count();double fps = static_cast(frameCount) / elapsedTime;//显示帧率putText(*frame, "FPS:" + to_string(fps), Point(20, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 0), 2);imshow("imgRead", *frame);// 退出循环条件(按下'Esc'键退出)if (waitKey(1) == '27'){break;}}}else if (mode == 2){const wchar_t* WindowTitle = L"选择需要传入的图像文件";Mat ImgRead = imread(openFile(WindowTitle));if (ImgRead.empty()){cerr << "无法读取图像文件或未选取文件" << endl;return -1;}reconizeShape(ImgRead, 1, 1, 1, 0);//形状识别相关函数(传入图像,是否截取形状,是否复刻原图,是否检测颜色,是否进入摄像机模式)imshow("img", ImgRead);// 退出循环条件(按下'Esc'键退出)waitKey(0);}} while (mode != 1 && 2);waitKey(0);system("pause");return 0;
}

​ a. 颜色识别部分只通过色度来判断,而非整体的HSV,因此可能比较不准确。

​ b. 矩形色区(用于提取H值并识别颜色的区域)的选取或许会出现超出目标内部范围的问题。

​ c. 摄像机图像处理在复杂场景下不稳定,还需加强。

_opencv图像识别形状_opencv形状识别

三、效果展示

四、遇到的问题及解决方法

​ 通过学习基本的图像处理技术,如边缘检测和轮廓提取,我逐渐掌握了如何在图像中寻找形状。这是一个让我感到满足的过程,因为我可以看到如何将一堆像素转化为有意义的信息。

​ 刚开始我还是个零基础的编程小白,但通过学习鱼实践我逐渐学会了编写有结构的代码,给变量和函数取有意义的名字,以及添加注释来解释我的代码。这有助于我更容易理解和维护自己的程序。

​ 一开始我用霍夫圆变换来检测圆,但是霍夫圆变换不能实现多角度识别圆形,于是我通过获取圆度(周长平方/4倍面积)来检测圆;一开始不知道有凸包检测,便只通过角点个数来判断五角星,但我细想这样把十边形也检测为五角星,于是我查找是否有能检测凸角的函数,通过各方社区,终于给我找到了凸包检测。

总的来说,作为一个新手,学习过程中的挑战使我更有动力不断学习和提高。我发现计算机视觉是一个充满无限可能的领域,而是我进入这个领域的理想起点。我期待着在未来的项目中继续探索的潜力,学到更多的知识,以及应用它在实际生活中。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了