openCV3.0 C++ 学习笔记补充(自用 代码+注释)---持续更新 三(61-)

环境:OpenCV3.2.0 + VS2017

61、轮廓集合重排序(按轮廓面积从小到大)

//对轮廓集合面积从大到小排序
bool compareValue_bs(const std::vector<cv::Point> & c1, const std::vector<cv::Point> & c2)
{int area1 = cv::contourArea(c1);int area2 = cv::contourArea(c2);return area1 > area2;
}
	std::vector<std::vector<cv::Point>> ENDcontour;std::vector<std::vector<cv::Point>> contours;std::vector<cv::Vec4i> hierarchy;std::vector<std::vector<cv::Point>>::iterator k;    //迭代器,访问容器数据cv::findContours(thresholdMat, contours, hierarchy, cv::RETR_EXTERNAL, CV_RETR_LIST); //查找外轮廓,压缩存储轮廓点std::sort(contours.begin(), contours.end(), compareValue_bs);
排序前
排序后

62、只删除过小轮廓及挨边轮廓

	bool deleteSmallMat(cv::Mat thresholdMat, cv::Mat &resMat, int minSize = 30, bool debug = false);
bool PlaneRec::deleteSmallMat(cv::Mat thresholdMat, cv::Mat &resMat, int minSize, bool debug)
{thresholdMat.copyTo(resMat);std::vector<cv::Rect> boundRect;std::vector<cv::RotatedRect> minRect;cv::Mat visual_bR;if (debug) thresholdMat.copyTo(visual_bR);if (visual_bR.type() != CV_8UC3) cv::cvtColor(visual_bR, visual_bR, cv::COLOR_GRAY2BGR);std::vector<std::vector<cv::Point>> ENDcontour;std::vector<std::vector<cv::Point>> contours;std::vector<cv::Vec4i> hierarchy;std::vector<std::vector<cv::Point>>::iterator k;    //迭代器,访问容器数据cv::findContours(thresholdMat, contours, hierarchy, cv::RETR_EXTERNAL, CV_RETR_LIST); //查找外轮廓,压缩存储轮廓点std::sort(contours.begin(), contours.end(), compareValue_bs);if (debug) printf("\n\n\n\n\n");if (contours.size() <= 0)//图为全黑时{std::cout << __FUNCTION__ << "cons.size() <= 0";//return false;}if (debug) printf("图像处理后 检测到的轮廓数 cons.size() = %d  \n", contours.size());int remainNum = 0;//剩余的轮廓数(有重画出来的轮廓数)cv::Mat  tmpMat = cv::Mat(thresholdMat.rows, thresholdMat.cols, CV_8UC1, cv::Scalar(0, 0, 0));//画出轮廓;int  count = 0;for (k = contours.begin(); k != contours.end(); ++k, count++) //删除小连通域的{std::vector<cv::Point> curContours = *k;if (curContours.size() < minSize) {cv::drawContours(resMat, contours, count, cv::Scalar(0, 0, 0), -1, CV_AA, hierarchy);cv::drawContours(resMat, contours, count, cv::Scalar(0, 0, 0), 2, CV_AA, hierarchy);continue;}remainNum++;if (1) {int area1 = cv::contourArea(curContours);if (debug) cout << __FUNCTION__ << "  count: " << count << ", area1=" << area1 << endl;}minRect.push_back(cv::minAreaRect(curContours));boundRect.push_back(cv::boundingRect(curContours));if (debug) cv::rectangle(visual_bR, boundRect[boundRect.size() - 1].tl(), boundRect[boundRect.size() - 1].br(), cv::Scalar(0, 255, 0), 1);if (debug) cv::putText(visual_bR, std::to_string(boundRect.size() - 1), boundRect[boundRect.size() - 1].tl(), cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(255, 135, 160), 1);if (debug) cv::putText(visual_bR, std::to_string(boundRect.size() - 1), boundRect[boundRect.size() - 1].br(), cv::FONT_HERSHEY_COMPLEX, 0.45, cv::Scalar(255, 135, 160), 1);if (debug) cv::drawContours(visual_bR, contours, count, cv::Scalar(255, 135, 160), -1, CV_AA, hierarchy);if (debug) {cv::circle(visual_bR, minRect.at(minRect.size() - 1).center, 3, cv::Scalar(0, 0, 255), -1, 8);  //绘制最小外接矩形的中心点cv::Point2f rect[4];minRect.at(minRect.size() - 1).points(rect);  //把最小外接矩形四个端点复制给rect数组for (int j = 0; j < 4; j++) {cv::line(visual_bR, rect[j], rect[(j + 1) % 4], cv::Scalar(0, 0, 255), 1, 8);  //绘制最小外接矩形每条边}}//if (boundRect.at(boundRect.size() - 1).height < src.rows / 5) continue;//轮廓是长度比图像的1/5短则直接过掉if (boundRect.size() > 0) {cv::Rect curBR = boundRect.at(boundRect.size() - 1);cv::RotatedRect curMR = minRect.at(minRect.size() - 1);double whRatio = curBR.width*1.0 / curBR.height;//宽高比double longMR = curMR.size.width;double shortMR = curMR.size.height;longMR = curMR.size.width > curMR.size.height ? curMR.size.width : curMR.size.height;shortMR = curMR.size.width < curMR.size.height ? curMR.size.width : curMR.size.height;double wh_MR_Ratio = longMR * 1.0 / shortMR;//非垂直的外接矩形框的长边短边比int area = cv::contourArea(curContours);double curS_tect = longMR * shortMR;//非垂直最小外接矩形面积double aRetio = area / curS_tect;//轮廓本身与非垂直最小外接矩形的面积比值if (shortMR <= 10) {cv::drawContours(resMat, contours, count, cv::Scalar(0, 0, 0), -1, CV_AA, hierarchy);cv::drawContours(resMat, contours, count, cv::Scalar(0, 0, 0), 2, CV_AA, hierarchy);continue;}if (curBR.x == 0 ||curBR.y == 0 ||curBR.x + curBR.width >= thresholdMat.cols ||curBR.y + curBR.height >= thresholdMat.rows) {cv::drawContours(resMat, contours, count, cv::Scalar(0, 0, 0), -1, CV_AA, hierarchy);cv::drawContours(resMat, contours, count, cv::Scalar(0, 0, 0), 2, CV_AA, hierarchy);continue;//挨边的删掉}if (debug) printf("area = %d, curS_rect=%lf, aRetio=%lf  \n", area, curS_tect, aRetio);if (aRetio >= 0.9) {//continue;}if (debug) cout << "--- curBR_" << boundRect.size() - 1 << curBR << whRatio << "\t";if (debug) cout << "   \tMR.angle=" << curMR.angle << "          \t, MR.center=" << curMR.center << "    \t, MR.points=" << curMR.size << ", wh_MR_Ratio" << wh_MR_Ratio << endl;//if (whRatio > 1) continue;//宽高比不满足要求的直接 continue}ENDcontour.push_back(curContours);cv::drawContours(tmpMat, contours, count, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy);}if (debug) cv::namedWindow("visual_bR222", cv::NORMCONV_FILTER);if (debug) cv::imshow("visual_bR222", visual_bR);if (debug) cv::imshow("tmpMat222", tmpMat);//tmpMat.copyTo(resMat);return true;
}
	deleteSmallMat(thresholdMat, thresholdMat, 30, debug);

63、获取轮廓点集

初始版:

		std::vector<cv::Point> curContours = *k;cv::Mat  curMat = cv::Mat(thresholdMat.rows, thresholdMat.cols, CV_8UC1, cv::Scalar(0, 0, 0));float peri = cv::arcLength(curContours, true);cv::approxPolyDP(curContours, conPoly[count], 0.02 * peri, true);cv::drawContours(curMat, contours, count, cv::Scalar(255, 255, 255), -1,cv::LINE_8, hierarchy);if (debug)cv::namedWindow("curMat", cv::NORMCONV_FILTER);if (debug) cv::imshow("curMat", curMat);if (1) {//找白的,白占比大于  才认为是小圆角cv::Mat imgReadOriPv;//原图上轮廓的对应位置imgGray.copyTo(imgReadOriPv, curMat);if (debug) cv::imshow("imgReadOriPv", imgReadOriPv);cv::threshold(imgMark, imgMark, 105, 255, cv::THRESH_BINARY);cv::Mat open;int tempk = 3;cv::Mat imgDil;cv::dilate(curMat, imgDil, cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(tempk, tempk)));if (debug)cv::namedWindow("dilate-WriteMat2", cv::NORMCONV_FILTER);if (debug) cv::imshow("dilate-WriteMat2", imgDil);//cv::erode(dil, open, cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(tempk, tempk)));imgDil.copyTo(open);open = open ^ curMat;//if (debug)cv::namedWindow("open-WriteMat2", cv::NORMCONV_FILTER);//if (debug) cv::imshow("open-WriteMat2", open);cv::threshold(open, open, 254, 255, cv::THRESH_BINARY);if (debug)cv::namedWindow("imgConEdge-WriteMat3", cv::NORMCONV_FILTER);if (debug) cv::imshow("imgConEdge-WriteMat3", open);//膨胀后减原轮廓只余下轮廓外圈,以获取边缘点集cv::Point startPnt = curContours[0];//第一个点for (int row = 0; row < open.rows; row++) {for (int col = 0; col < open.cols; col++) {cv::Point curp = cv::Point(col, row);if (open.at<uchar>(curp) >= 205) {startPnt = curp;break;}}}//if (debug) cout << "----------------- open.size()=" << open.size() << ", startPnt" << startPnt << endl;//if (debug) circle(open, startPnt, 2, cv::Scalar(0, 0, 0), cv::FILLED);if (1) {//轮廓完整点集 //为了测试轮廓形态对比 先原图像素值判定0914cxlvector<cv::Point> conPntLst;cv::Mat imgFindPnt;curMat.copyTo(imgFindPnt);cv::Mat imgFound = cv::Mat::zeros(imgFindPnt.size(), CV_8UC1);getPntLst_dfs_clockwise(imgFindPnt, imgFound, conPntLst, startPnt, 140);//以顺时针沿外边缘的顺序存入//if (debug) cout << "-----------------conPntLst.size()=" << conPntLst.size() << endl;if (debug) cv::imshow("imgFound", imgFound);if (0) {//可视化cv::Mat imgF111ound = cv::Mat::zeros(imgFindPnt.size(), CV_8UC1);if (debug) circle(imgF111ound, startPnt, 2, cv::Scalar(255, 255, 255), cv::FILLED);for (cv::Point curp : conPntLst) {if (debug) cout << "*** startPnt=" << curp << endl;imgFindPnt.at<uchar>(curp) = 0;if (debug) cv::imshow("visual_conPntLst", imgFindPnt);imgF111ound.at<uchar>(curp) = 255;if (debug) cv::imshow("img--------------ound", imgF111ound);//if (debug) cv::waitKey(51);}}double avgPv = 0;for (cv::Point curp : conPntLst) {int pv = imgReadOriPv.at<uchar>(curp);avgPv += pv;}avgPv /= conPntLst.size();if (debug) cout << "-----------------avgPv=" << avgPv << endl;if (avgPv <= 200) {//轮廓对应原图上不够白的小轮廓,认为不是小圆角cv::drawContours(thresholdMat, contours, count, cv::Scalar(0, 0, 0), -1, CV_AA, hierarchy);cv::drawContours(thresholdMat, contours, count, cv::Scalar(0, 0, 0), 3, CV_AA, hierarchy);continue;//不要了}}if (0) {//轮廓外边缘点集//cv::Mat  newMat = cv::Mat(thresholdMat.rows, thresholdMat.cols, CV_8UC1, cv::Scalar(0, 0, 0));//drawContours(newMat, conPoly, count, cv::Scalar(255, 255, 255), 1);//drawContours(open, conPoly, count, cv::Scalar(255, 255, 255), 1);vector<cv::Point> conPntLst;cv::Mat imgFindPnt;open.copyTo(imgFindPnt);//newMat.copyTo(imgFindPnt);cv::Mat imgFound = cv::Mat::zeros(imgFindPnt.size(), CV_8UC1);getPntLst_dfs_clockwise(imgFindPnt, imgFound, conPntLst, startPnt, 140);//以顺时针沿外边缘的顺序存入if (debug) cout << "-----------------conPntAllLst.size()=" << conPntLst.size() << endl;if (debug) cv::imshow("imgFound", imgFound);if (1) {//可视化cv::Mat imgF111ound = cv::Mat::zeros(imgFindPnt.size(), CV_8UC1);if (debug) circle(imgF111ound, startPnt, 1, cv::Scalar(255, 255, 255), cv::FILLED);for (cv::Point curp : conPntLst) {if (debug) cout << "*** startPnt=" << curp << endl;imgFindPnt.at<uchar>(curp) = 0;if (debug) cv::imshow("visual_conPntLst", imgFindPnt);imgF111ound.at<uchar>(curp) = 255;if (debug) cv::imshow("img--------------ound", imgF111ound);if (debug) cv::waitKey(51);}}if (1) {std::vector<double> resList;int res = getAngleChange(conPntLst, resList);for (int i = 0; i < resList.size(); ++i) {if (debug) std::cout << resList[i] / (2.0*PI) * 360 << " -> ";}std::vector<double> trend;trend = get_trendList(resList, 1, debug);resList = trend;if (1) {int smoothCnt = 2;std::vector<double> newWLst = resList;int curCnt = smoothCnt;while (curCnt--) {linearSmooth3(newWLst, newWLst, 1);}resList = newWLst;}if (1) {if (debug) printf("disList.size()= %d \n", resList.size());float mean, variance, standard_deviation;get_meanCorrelationTest(resList, mean, variance, standard_deviation);if (debug) printf("disList 均值: %f  \n", mean); // 均值if (debug) printf("disList 方差: %f  \n", variance); // 方差if (debug) printf("disList 标准差: %f  \n\n", standard_deviation); // 标准差}if (debug) showLine(resList);}}//轮廓外边缘点集}

64、获取满足阈值的连通域点集(深搜,顺时针搜索存入)

/*
//以深搜的方式,顺时针方向获取轮廓外边缘点集
#include <stack> 
cv::Mat& src, cv::Mat& matDst, 搜索结果可视化标识
vector<cv::Point> &conPntLst, 获取到的轮廓边缘点集
cv::Point2i startPnt, 起始种子点
int th,像素值大于该值才被认为是轮廓部分
*/
void getPntLst_dfs_clockwise(cv::Mat& src, cv::Mat& matDst, vector<cv::Point> &conPntLst, cv::Point2i startPnt, int th)
{//cout << __FUNCTION__ << " conPntLst.size()=" << conPntLst.size() << ", startPnt" << startPnt << endl;stack<cv::Point> ptStack;//种子点队列//搜索方向顺序数据int DIR[8][2] = { { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 }, { -1, -1 } };//从上往右顺时针搜ptStack.push(startPnt);//起始种子点入栈conPntLst.clear();while (!ptStack.empty()) {cv::Point curp = ptStack.top();ptStack.pop();conPntLst.push_back(curp);//分别对八个方向上的点进行生长for (int i = 0; i < 8; ++i) {cv::Point tmpp;tmpp.x = curp.x + DIR[i][0];tmpp.y = curp.y + DIR[i][1];//检查是否是边缘点if (tmpp.x < 0 ||tmpp.y < 0 ||tmpp.x > (src.cols - 1) ||tmpp.y > (src.rows - 1)) {continue;}int nGrowLable = matDst.at<uchar>(tmpp.y, tmpp.x);	//是否已搜过if (nGrowLable == 0) {//未搜过int nCurValue = src.at<uchar>(tmpp.y, tmpp.x);//是否属于轮廓if (nCurValue >= th) {//属于轮廓matDst.at<uchar>(tmpp.y, tmpp.x) = 255;	//标记为已搜过ptStack.push(tmpp);}}}}
}

调用示例:

    cv::Point startPnt = curContours[0];//起始第一个点for (int row = 0; row < open.rows; row++) {for (int col = 0; col < open.cols; col++) {cv::Point curp = cv::Point(col, row);if (open.at<uchar>(curp) >= 205) {startPnt = curp;break;}}}vector<cv::Point> conPntLst;cv::Mat imgFindPnt;open.copyTo(imgFindPnt);//newMat.copyTo(imgFindPnt);cv::Mat imgFound = cv::Mat::zeros(imgFindPnt.size(), CV_8UC1);getPntLst_dfs_clockwise(imgFindPnt, imgFound, conPntLst, startPnt, 140);//以顺时针沿外边缘的顺序存入if (debug) cout << "-----------------conPntAllLst.size()=" << conPntLst.size() << endl;if (debug) cv::imshow("imgFound", imgFound);if (1) {//可视化(点集及其存入顺序)cv::Mat imgF111ound = cv::Mat::zeros(imgFindPnt.size(), CV_8UC1);if (debug) circle(imgF111ound, startPnt, 2, cv::Scalar(255, 255, 255), cv::FILLED);for (cv::Point curp : conPntLst) {if (debug) cout << "*** startPnt=" << curp << endl;imgFindPnt.at<uchar>(curp) = 0;if (debug) cv::imshow("visual_conPntLst", imgFindPnt);imgF111ound.at<uchar>(curp) = 255;if (debug) cv::imshow("img--------------ound", imgF111ound);if (debug) cv::waitKey(51);}}

65、从轮廓中获取所需点集(轮廓外边缘点集/轮廓完整点集)

/*
//从轮廓中获取所需点集(轮廓外边缘点集/轮廓完整点集)
cv::Mat imgOriginal, 提供图像尺寸大小
std::vector<cv::Point> curContour, 依据轮廓
cv::Mat& matDst, 搜索结果可视化标识
vector<cv::Point> &conPntLst, 获取到的轮廓边缘点集(第一个点是图像最上的轮廓白点)
int mode, 模式:0为获取轮廓外边缘点集(以顺时针沿外边缘的顺序存入),1为获取轮廓完整点集
*/
void getPntLst_fromContour(cv::Mat imgOriginal, std::vector<cv::Point> curContour, cv::Mat& imgFound, vector<cv::Point> &conPntLst, int mode = 1, bool debug = false);
/*
//从轮廓中获取所需点集(轮廓外边缘点集/轮廓完整点集)
cv::Mat imgOriginal, 提供图像尺寸大小
std::vector<cv::Point> curContour, 依据轮廓
cv::Mat& matDst, 搜索结果可视化标识
vector<cv::Point> &conPntLst, 获取到的轮廓边缘点集(第一个点是图像最上的轮廓白点)
int mode, 模式:0为获取轮廓外边缘点集(以顺时针沿外边缘的顺序存入),1为获取轮廓完整点集
*/
void getPntLst_fromContour(cv::Mat imgOriginal, std::vector<cv::Point> curContour, cv::Mat& imgFound, vector<cv::Point> &conPntLst, int mode, bool debug) 
{if (curContour.empty()) return;imgFound = cv::Mat::zeros(imgOriginal.size(), CV_8UC1);std::vector<cv::Point> curContours = curContour;cv::Mat  curMat = cv::Mat(imgOriginal.rows, imgOriginal.cols, CV_8UC1, cv::Scalar(0, 0, 0));//当前轮廓std::vector<std::vector<cv::Point>> contours;contours.push_back(curContours);cv::drawContours(curMat, contours, 0, cv::Scalar(255, 255, 255), -1, cv::LINE_8);if (debug)cv::namedWindow("curMat", cv::NORMCONV_FILTER);if (debug) cv::imshow("curMat", curMat);cv::Mat imgFindPnt;curMat.copyTo(imgFindPnt);if (mode == 0) {cv::Mat imgConEdge;//轮廓外边缘if (0) {//实验证明用形态学梯度回导致轮廓边缘有两层点集cv::morphologyEx(curMat, imgConEdge, cv::MORPH_GRADIENT, cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3)));}else {//为了使轮廓边缘只余一层点集,选择用膨胀后与原图取异或cv::Mat imgDil;int tempk = 3;cv::dilate(curMat, imgDil, cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(tempk, tempk)));if (debug)cv::namedWindow("dilate-ConEdge", cv::NORMCONV_FILTER);if (debug) cv::imshow("dilate-ConEdge", imgDil);imgDil.copyTo(imgConEdge);imgConEdge = imgConEdge ^ curMat;cv::threshold(imgConEdge, imgConEdge, 254, 255, cv::THRESH_BINARY);}if (debug)cv::namedWindow("imgConEdge", cv::NORMCONV_FILTER);if (debug) cv::imshow("imgConEdge", imgConEdge);//膨胀后减原轮廓只余下轮廓外圈,以获取边缘点集imgConEdge.copyTo(imgFindPnt);}else if (mode == 1) {curMat.copyTo(imgFindPnt);}cv::Point startPnt = curContours[0];//第一个点for (int row = 0; row < imgFindPnt.rows; row++) {for (int col = 0; col < imgFindPnt.cols; col++) {cv::Point curp = cv::Point(col, row);if (imgFindPnt.at<uchar>(curp) >= 205) {startPnt = curp;break;}}}//if (debug) cout << "----------------- imgFindPnt.size()=" << imgFindPnt.size() << ", startPnt" << startPnt << endl;//if (debug) circle(open, startPnt, 2, cv::Scalar(0, 0, 0), cv::FILLED);getPntLst_dfs_clockwise(imgFindPnt, imgFound, conPntLst, startPnt, 140);//以顺时针沿外边缘的顺序存入//if (debug) cout << "-----------------conPntLst.size()=" << conPntLst.size() << endl;if (debug) cv::imshow("imgFound", imgFound);if (0) {//可视化(点集及其存入顺序)cv::Mat imgF111ound = cv::Mat::zeros(imgFindPnt.size(), CV_8UC1);if (debug) circle(imgF111ound, startPnt, 1, cv::Scalar(255, 255, 255), cv::FILLED);for (cv::Point curp : conPntLst) {if (debug) cout << "*** startPnt=" << curp << endl;imgFindPnt.at<uchar>(curp) = 0;if (debug) cv::imshow("visual_conPntLst", imgFindPnt);imgF111ound.at<uchar>(curp) = 255;if (debug) cv::imshow("img--------------ound", imgF111ound);if (debug) cv::waitKey(51);}}
}

调用示例:

    //轮廓完整点集vector<cv::Point> conPntLst;cv::Mat imgFound;getPntLst_fromContour(imgOriginal, curContours, imgFound, conPntLst, 1, debug);//找白的,白占比大于  才认为是小圆角cv::Mat imgReadOriPv;//原图上轮廓的对应位置imgGray.copyTo(imgReadOriPv, curMat);if (debug) cv::imshow("imgReadOriPv", imgReadOriPv);double avgPv = 0;for (cv::Point curp : conPntLst) {int pv = imgReadOriPv.at<uchar>(curp);avgPv += pv;}avgPv /= conPntLst.size();if (debug) cout << "-----------------avgPv=" << avgPv << endl;if (avgPv <= 200) {//轮廓对应原图上不够白的小轮廓,认为不是小圆角cv::drawContours(thresholdMat, contours, count, cv::Scalar(0, 0, 0), -1, CV_AA, hierarchy);cv::drawContours(thresholdMat, contours, count, cv::Scalar(0, 0, 0), 3, CV_AA, hierarchy);continue;//不要了}
    //轮廓外边缘点集vector<cv::Point> conPntLst;cv::Mat imgFound;getPntLst_fromContour(imgOriginal, curContours, imgFound, conPntLst, 0, debug);if (1) {std::vector<double> resList;int res = getAngleChange(conPntLst, resList);for (int i = 0; i < resList.size(); ++i) {if (debug) std::cout << resList[i] / (2.0*PI) * 360 << " -> ";}std::vector<double> trend;trend = get_trendList(resList, 1, debug);resList = trend;if (1) {int smoothCnt = 2;std::vector<double> newWLst = resList;int curCnt = smoothCnt;while (curCnt--) {linearSmooth3(newWLst, newWLst, 1);}resList = newWLst;}if (1) {if (debug) printf("disList.size()= %d \n", resList.size());float mean, variance, standard_deviation;get_meanCorrelationTest(resList, mean, variance, standard_deviation);if (debug) printf("disList 均值: %f  \n", mean); // 均值if (debug) printf("disList 方差: %f  \n", variance); // 方差if (debug) printf("disList 标准差: %f  \n\n", standard_deviation); // 标准差}if (debug) showLine(resList);
	static void showLine(std::vector<double>posList, bool debug = false);void PlaneRec::showLine(std::vector<double> posList, bool debug)
{if (posList.size() < 2) {return;}int maxVar = 360 + 1;int minVar = -360 - 1;cv::Mat canva = cv::Mat::zeros(cv::Size(posList.size()*10 + 1, maxVar - minVar), CV_8UC3);cv::Point startPos(0,(int)posList[0] / (2.0*PI) * 360 + maxVar);for (int i = 1; i < posList.size(); ++i) {double tmp = posList[i] / (2.0*PI) * 360 + maxVar;cv::Point posEnd(i*10, (int)tmp);//canva.at<cv::Vec3b>(posEnd) = cv::Vec3b(255, 255, 255);cv::line(canva, startPos, posEnd, cv::Scalar(255,255,255), 3, 8);startPos = posEnd;}if (debug) cv::namedWindow("showLine", cv::NORMCONV_FILTER);if (debug) cv::imshow("showLine", canva);
}

66、删除轮廓(不再会误删被包围在中间的内圈小轮廓)

前提:

直接轮廓查找后,利用cv::drawContours()涂黑。

	//cv::drawContours(resMat, contours, count, cv::Scalar(0, 0, 0), -1, CV_AA, hierarchy);//cv::drawContours(resMat, contours, count, cv::Scalar(0, 0, 0), 2, CV_AA, hierarchy);

一旦出现:需要删除的轮廓中 完整包含着 不需要删除的小轮廓 在其内圈,

则会在删除的同时将小轮廓也一起误删。

为避免这种情况,则需按连通域来进行删除。操作如下:

1)获取待删除轮廓对应的连通域,即其完整轮廓点集。

2)然后一个点一个点地去进行涂黑删除。

即可。

如此则不会误删其包含在内部的小轮廓。

	for (k = contours.begin(); k != contours.end(); ++k, count++) //删除小连通域的{std::vector<cv::Point> curContours = *k;cv::Mat curMat = cv::Mat(imgOriginal.rows, imgOriginal.cols, CV_8UC1, cv::Scalar(0, 0, 0));//当前轮廓cv::drawContours(curMat, contours, count, cv::Scalar(255, 255, 255), -1, cv::LINE_8);vector<cv::Point> conPntAllLst;//轮廓完整点集 if (1) {//以便将连通域位置删除而不会误删大轮廓包含在内的小轮廓cv::Mat imgFindPnt;curMat.copyTo(imgFindPnt);cv::Mat imgFound = cv::Mat::zeros(imgFindPnt.size(), CV_8UC1);cv::Point startPnt = curContours[0];//第一个点getPntLst_dfs_clockwise(imgFindPnt, imgFound, conPntAllLst, startPnt, 140);//以顺时针沿外边缘的顺序存入//if (debug) cout << "-----------------conPntLst.size()=" << conPntLst.size() << endl;if (debug) cv::imshow("imgFound", imgFound);if (0) {//可视化cv::Mat imgF111ound = cv::Mat::zeros(thresholdMat.size(), CV_8UC1);for (cv::Point curp : conPntAllLst) {if (debug) cout << "*** startPnt=" << curp << endl;thresholdMat.at<uchar>(curp) = 0;if (debug) cv::imshow("visual_conPntLst", thresholdMat);imgF111ound.at<uchar>(curp) = 255;if (debug) circle(imgF111ound, startPnt, 2, cv::Scalar(255, 255, 255), cv::FILLED);if (debug) cv::imshow("img--------------ound", imgF111ound);//if (debug) cv::waitKey(51);}}}//需要删除的轮廓,则轮廓对应位置涂黑for (cv::Point curp : conPntAllLst) {resMat.at<uchar>(curp) = 0;//轮廓对应位置涂黑}}

拓展:改一下画轮廓的方式

	if (0) {cv::drawContours(tmpMat, contours, i, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy);}else {//改一下画轮廓的方式vector<cv::Point> conPntAllLst;//轮廓完整点集 if (1) {//以便将连通域位置删除而不会误删大轮廓包含在内的小轮廓cv::Mat imgFindPnt;thresholdMat.copyTo(imgFindPnt);cv::Mat imgFound = cv::Mat::zeros(imgFindPnt.size(), CV_8UC1);cv::Point startPnt = curContours[0];//第一个点getPntLst_dfs_clockwise(imgFindPnt, imgFound, conPntAllLst, startPnt, 140);//以顺时针沿外边缘的顺序存入//if (debug) cout << "-----------------conPntLst.size()=" << conPntLst.size() << endl;if (debug) cv::imshow("imgFound", imgFound);if (0) {//可视化cv::Mat imgF111ound = cv::Mat::zeros(thresholdMat.size(), CV_8UC1);for (cv::Point curp : conPntAllLst) {if (debug) cout << "*** startPnt=" << curp << endl;thresholdMat.at<uchar>(curp) = 0;if (debug) cv::imshow("visual_conPntLst", thresholdMat);imgF111ound.at<uchar>(curp) = 255;if (debug) circle(imgF111ound, startPnt, 2, cv::Scalar(255, 255, 255), cv::FILLED);if (debug) cv::imshow("img--------------ound", imgF111ound);//if (debug) cv::waitKey(51);}}}for (cv::Point curp : conPntAllLst) tmpMat.at<uchar>(curp) = 255;//轮廓对应位置涂白}

 

67、

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/145225.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【Python进阶】requests库有哪些常用的参数和方法?一篇文章带你详细了解!!!附带源码

常用的requests库参数和方法 常用方法 requests库中定义了多个常用的请求方法&#xff0c;其中requests.get()和requests.post()是最常用的方法。这些方法对应于HTTP协议中的GET和POST方法。 requests.get(url, paramsNone, **kwargs): 用于发送GET请求。requests.post(url…

116页可编辑PPT全面了解数据治理体系、平台,数据质量数据标准

概览 《行业大数据治理平台》是一个全面深入探讨大数据治理的PPT文档&#xff0c;共116页&#xff0c;涵盖了建设背景、解决方案、核心功能以及实际应用案例等多个方面。 核心议题 数据作为资产的重要性和全生命周期管理。信息系统建设方案的演变及其面临的问题。数据资产运营…

鸿蒙Harmony-Next 徒手撸一个日历控件

本文将介绍如何使用鸿蒙Harmony-Next框架实现一个自定义的日历控件。我们将创建一个名为CalendarView的组件&#xff08;注意,这里不能叫 Calendar因为系统的日历叫这个&#xff09;,它具有以下功能: 显示当前月份的日历支持选择日期显示农历日期可以切换上一月和下一月 组件…

[译] Go语言的源起,发展和未来

本篇内容是根据2019年9月份Creating the Go programming language音频录制内容的整理与翻译, 两位主持人与Go 的创始人 Rob Pike 和 Robert Griesemer谈论了 Go 的起源、发展、影响和未来。这是一个史诗般的剧集&#xff0c;深入探讨了 Go 的历史和详细信息&#xff0c;以及他们…

web基础—dvwa靶场(十一)CSP Bypass

CSP Bypass(CSP 绕过) 内容安全策略&#xff08;CSP&#xff09;用于定义脚本和其他资源可以从何处加载或执行&#xff0c;本模块将指导您根据开发人员犯下的常见错误来绕过该策略。 这些漏洞都不是 CSP 中的实际漏洞&#xff0c;它们都是实现 CSP 的方式中的漏洞。 绕过内容安…

JAVA——IO_缓冲流

目录 一、字节缓冲流 二、字符缓冲流 字符缓冲输入流( BufferedReader ) 字符缓冲输出流&#xff08; BufferedWriter ) 缓冲流作用&#xff1a;对原始流进行包装&#xff0c;以提高原始流读写数据的性能 一、字节缓冲流 1. 作用&#xff1a;提高字节流读写数据的性能 2…

使用scp命令从本地往服务器传输文件失败

解决办法&#xff1a; 找到这个文件&#xff0c;打开&#xff0c;将里面的服务器ip对应的一行数据删掉即可。

【Python报错已解决】To update, run: python.exe -m pip install --upgrade pip

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

麒麟操作系统快捷键设置

这些是银河麒麟操作系统常用的快捷键&#xff0c;和Windows系统有点儿相似。 但也有一些快捷键为未列出来&#xff0c;如CtrlALTT打开终端&#xff0c;Ctrld关闭终端&#xff0c;F2&#xff1a;重命名&#xff1b; CtrlshiftN&#xff1a;新建文件夹。

虚拟机ens33网卡不显示inet地址(已设置NOBOOT为yes)

在虚拟机中输入ifconfig或ip addr时&#xff0c;出现如下情况&#xff1a; sudo dhclient ens33sudo ifconfig ens33依次执行上面两行&#xff0c;之后发现ens33中可以显示inet了 本虚拟机的地址就是192.168.244.131

ABAP 一步一步教你添加ALV界面菜单功能按钮

ABAP 一步一步教你添加菜单功能按钮。 程序里面找到这个组件小按钮 就可以看到GUI状态了。 在修改GUI STATUS 是如果要添加一个功能按钮&#xff0c;必须先创建一个功能键&#xff08;具体参照下方&#xff09;&#xff0c;之后再在应用程序工具栏输入该功能键的功能码否则报…

Windows上创建批处理.bat文件并且注册为开机自启(Python-web微服务)

1. winodws桌面点击创建文本文件 &#xff08;文件名称.txt&#xff09; 2. 将如下代码写入txt文件中 echo off if "%1""h" goto begin start mshta vbscript:createobject("wscript.shell").run("""%~nx0"" h"…

百元学生党头戴式耳机选哪个?四款热门天花板机型推荐

当前市场上&#xff0c;耳机产品的竞争愈发激烈&#xff0c;降噪技术也日益精进。回想过去&#xff0c;要想享受到优质的降噪体验&#xff0c;动辄需要花费数千元&#xff0c;但现在&#xff0c;高品质的降噪耳机已经降至百元级别。在众多降噪耳机中&#xff0c;头戴式耳机尤为…

网站SEO,该如何规范目标网站URL配置!

随着互联网技术的飞速发展&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;在网站建设和运营中的重要性日益凸显。优化目标网站的URL配置&#xff0c;作为SEO策略中的关键环节&#xff0c;对于提升网站在搜索引擎中的排名和曝光度具有至关重要的作用。大连蝙蝠侠科技将从U…

掌握IT资产发现的三个步骤

IT 资产生态系统非常复杂&#xff0c;因为资产不断变化&#xff0c;包括新增资产、移除过时资产或修改现有资产。在这种动态环境中&#xff0c;IT 资产管理者很难全面查看所有拥有的资产。 根据Gartner的预测&#xff0c;到 2025 年&#xff0c;大约 30% 的关键基础设施组织将…

Hutool树结构工具-TreeUtil构建树形结构

1 pom.xml <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.26</version> </dependency> 2 核心代码 import cn.beijing.satoken.domain.ZhiweiCityArea; import cn.beijing.sa…

机器人上的DPDK使用思考

引言 项目背景 人形机器人作为智能技术的集大成者&#xff0c;正逐步从科幻电影走进现实生活&#xff0c;广泛应用于工业制造、医疗健康、家庭服务等多个领域。在这一发展过程中&#xff0c;传感器技术的飞速发展和物联网技术的广泛应用&#xff0c;极大地提升了人形机器人对…

【AI视频】Runway:Gen-2 运镜详解

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI视频 | Runway 文章目录 &#x1f4af;前言&#x1f4af;Camera Control&#xff08;运镜&#xff09;&#x1f4af;Camera Control功能测试Horizonta&#xff08;左右平移&#xff09;Vertical&#xff08;上下平移&#xff0…

双token无感刷新

文章目录 &#x1f7e2;双token无感刷新1、token过期续期的五种方案对比2、双token的基本概念3、双token无感刷新的原理4、双token无感刷新的实现方式5.前端实现 ✒️总结 &#x1f7e2;双token无感刷新 对于token无感刷新这个东西有复杂度的话&#xff0c;它主要在后端&#x…

【使用Hey对vllm接口压测】模型并发能力

使用Hey对vllm进行模型并发压测 docker run --rm --networkknowledge_network \registry.cn-shanghai.aliyuncs.com/zhph-server/hey:latest \-n 200 -c 200 -m POST -H "Content-Type: application/json" \-H "Authorization: xxx" \-d {"model"…