1、批量访问图片,等待键盘

for (int i = 2; i <= 23;){if (KEY_DOWN('S')){std::string  path = "";char tmpChar[255];sprintf(tmpChar, "C:\\Users\\yxh20\\Desktop\\text\\FilletWeld\\img%d.png", i);path = tmpChar;cv::Mat srcImage;srcImage = cv::imread(path, 1);printf("*********************************【 Openc第 %d 次调用 】 ***************************** \n", i);ImageProcessing(srcImage);srcImage.release();i++;}else{Sleep(20);//循环时间间隔,防止太占内存 }}

可用:

 vector<Mat> images;         // another thing. use english for variable names, nothing else...for (int i = 1; i <= 23; i++)  // a <=Count would do one too many...{string name = format("F:\\project\\ArcPositioning\\x64\\标克图片\\0223——关灯\\%d.bmp", i);Mat img = imread(name); // pgm implies grayscale, maybe even: imread(name,0); to return CV_8Uif (img.empty())      // please, *always check* resource-loading.{cerr << "whaa " << name << " can't be loaded!" << endl;continue;}images.push_back(img);// show result:imshow("test", img);waitKey();              // yes, you need the waitKey()}

可用:

void main()//山东 和 东莞
{ImageProcessing pd;bool   lianxu = false; //循环测试if (lianxu){cv::Mat imgOriginal;vector<cv::Point> resPoint;//山东//string path = cv::format("E:\\vsproject\\shandong_gezi\\shandong\\testImage\\65.bmp");//string path = cv::format("E:\\vsproject\\shandong_gezi\\shandong\\img\\ce245eb208bfc15e47e48bf24a70be7.png");//string path = cv::format("E:\\vsproject\\WeldingLine\\weldingLine\\testImage\\Image_20220610152040299.bmp");//东莞string path = cv::format("E:\\vsproject\\shandong_gezi\\shandong\\testImage2\\17.bmp");//6.28奇奇怪怪坡口 --- 东莞imgOriginal = cv::imread(path);// M 俯视//path = cv::format("E:\\vsproject\\shandong_gezi\\shandong\\testImage\\Image_20220614143156567.bmp");//imgOriginal = cv::imread(path);cv::Mat canvas;//可视化的画布//imgOriginal.copyTo(canvas);pj_in splice_i_mf = { 8, 8, 5, 5 };pj_out splice_o_mf;pd.M_LookDown(imgOriginal, splice_i_mf, splice_o_mf, resPoint, canvas, true);cv::imshow("原图imgOriginal", imgOriginal);cv::namedWindow("原图imgOriginal", cv::NORMCONV_FILTER);cvSetMouseCallback("原图imgOriginal", on_mouse_singleClick, 0);cout << "已走主函数!" << endl;cv::waitKey();}else{        //循环测试图像for (int i = 1; i <= 45; i++){cv::Mat imgOriginal;vector<cv::Point> resPoint;//string path = cv::format("E:\\vsproject\\shandong_gezi\\shandong\\testImage\\%d.bmp", i);//山东>拐角string path = cv::format("E:\\vsproject\\shandong_gezi\\shandong\\testImage2\\%d.bmp", i);//多层多道imgOriginal = cv::imread(path);// M 俯视//path = cv::format("E:\\vsproject\\shandong_gezi\\shandong\\testImage\\Image_20220614143156567.bmp");//imgOriginal = cv::imread(path);cv::Mat canvas;//可视化的画布imgOriginal.copyTo(canvas);pj_in splice_i_mf = { 8, 8, 5, 5 };pj_out splice_o_mf;pd.M_LookDown(imgOriginal, splice_i_mf, splice_o_mf, resPoint, canvas, false);cv::imshow("原图imgOriginal", imgOriginal);cv::namedWindow("原图imgOriginal", cv::NORMCONV_FILTER);cvSetMouseCallback("原图imgOriginal", on_mouse_singleClick, 0);cout << "已走主函数!" << endl;//string SAVEpath = cv::format("E:\\vsproject\\shandong_gezi\\shandong\\resultIMG\\%d_relust.bmp", i);//山东>拐角string SAVEpath = cv::format("E:\\vsproject\\shandong_gezi\\shandong\\resultIMG2\\%d_relust.bmp", i);//多层多道cv::imwrite(SAVEpath, canvas);printf("-------------------------------当前图片为: %d.bmp---------------------------------------------\n\n\n\n\n", i);cv::waitKey(50);}}system("pause");
}

2、求均值、方差、标准差


#include <numeric> //accumulate的头文件
#include <iostream>
#include <math.h>
#include <vector>
//头文件缺哪个补哪个吧,实在是忘了哪一个// 求均值float sum = std::accumulate(std::begin(middle_x_Lst), std::end(middle_x_Lst), 0.0);float mean = sum / middle_x_Lst.size();// 求方差与标准差float variance = 0.0;for (uint16_t i = 0; i < middle_x_Lst.size(); i++){variance = variance + pow(middle_x_Lst[i] - mean, 2);}variance = variance / middle_x_Lst.size();float standard_deviation = sqrt(variance);if(debug) printf("中点的x值 均值: %f  \n", mean); // 均值if(debug) printf("中点的x值 方差: %f  \n", variance); // 方差if(debug) printf("中点的x值 标准差: %f  \n\n", standard_deviation); // 标准差if(debug) std::cout << "中点的x值 均值: " << mean << std::endl; // 均值if(debug) std::cout << "中点的x值 方差: " << variance << std::endl; // 方差if(debug) std::cout << "中点的x值 标准差: " << standard_deviation << std::endl; // 标准差

3、将数据写入txt文件并保存到指定路径

 ofstream ofs("E:\\qtproject\\LK_CJY\\LK\\QtApp_Cylinder\\win64_exe\\release\\Log\\resultIMG\\mid_Y_Data.txt", ios::out | ios::app);if (ofs) {ofs << "图片序号:" << m_picNum << "  均值=" << mean << "  方差" << variance << "  标准差" << standard_deviation << endl;}ofs.close();

4、图像预处理相关

4.1 阈值、膨胀、删除最小连通域

threshold阈值(直方图二值化):可去噪

 cv::Mat grayMat;if (src.type() != CV_8UC1)cv::cvtColor(src, grayMat, cv::COLOR_BGR2GRAY);else src.copyTo(grayMat);if (debug){cv::imshow("src", src);//cv::imshow("grayMat", grayMat);}cv::Mat thresholdMat;cv::threshold(grayMat, thresholdMat, 130, 255, CV_THRESH_BINARY); //阈值150cv::Mat dilateMat;cv::Mat element;int s = 3;element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(s, s));cv::dilate(thresholdMat, dilateMat, element, cv::Point(-1, -1), 2); //调用膨胀APIstd::vector<std::vector<cv::Point>> contours;std::vector<cv::Vec4i> hierarchy;std::vector<std::vector<cv::Point>>::iterator k;    //迭代器,访问容器数据cv::findContours(dilateMat, contours, hierarchy, cv::RETR_EXTERNAL, CV_RETR_LIST); //查找外轮廓,压缩存储轮廓点vector<cv::Rect> boundRect;cv::Mat  tmpMat = cv::Mat(dilateMat.rows, dilateMat.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() < 750) continue;boundRect.push_back(cv::boundingRect(curContours));if (boundRect.at(boundRect.size() - 1).height < src.rows / 5) continue;//轮廓是长度比图像的1/5短则直接过掉cv::drawContours(tmpMat, contours, count, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充}//画出轮廓--法2://for (int i = 0; i < contours.size(); i++)//{//  std::vector<cv::Point> curContours = contours.at(i);//   if (curContours.size() < 70) continue;// cv::drawContours(tmpMat, contours, i, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充//}只画出最大的那个轮廓//int maxContou_size = 0;//int maxContou_index;//for (int i = 0; i < contours.size(); i++)//{// std::vector<cv::Point> curContours = contours.at(i);//   if (curContours.size() < 70) continue;// if (maxContou_size < curContours.size())//   {//     maxContou_size = curContours.size();//     maxContou_index = i;// }// //cv::drawContours(tmpMat, contours, i, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充//}//cv::drawContours(tmpMat, contours, maxContou_index, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //只画出最大的那个轮廓if (debug){cv::imshow("thresholdMat", thresholdMat);cv::imshow("dilateMat", dilateMat);cv::imshow("tmpMat", tmpMat);}

4.2 细化

函数:

cv::Mat thining_img(cv::Mat& src_, cv::Rect roi_, float level)//细化图像,level:1~4,等级1为特征点数更多
{if (level > 4) level = 4;else if (level < 0.5) level = 0.5;//  printf("roi:%d,%d\n", roi_.x, roi_.y);if (roi_.x < 0) roi_.x = 0;if (roi_.y < 0) roi_.y = 0;if (roi_.x + roi_.width > src_.cols) roi_.width = src_.cols - roi_.x;if (roi_.y + roi_.height > src_.rows) roi_.height = src_.rows - roi_.y;cv::Mat dst;cv::Mat src = src_(roi_);if (src.type() != CV_8UC1){//        printf("只能处理二值或灰度图像\n");cvtColor(src, src, CV_BGR2GRAY);}//预处理//blur(src, src, cv::Size(5, 5));//double max_val = 0;//cv::minMaxLoc(src, 0, &max_val, 0, 0);//cv::threshold(src, src, max_val *level / 5, 255, CV_THRESH_BINARY);/*cv::Mat element1 = getStructuringElement(cv::MORPH_CROSS, cv::Size(7, 7));cv::Mat element2 = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));dilate(src, src, element2);erode(src, src, element1);*///    medianBlur(src, src, 3);//非原地操作时候,copy src到dstif (dst.data != src.data){src.copyTo(dst);}int i, j, n;int width, height;//之所以减1,是方便处理8邻域,防止越界width = src.cols - 1;height = src.rows - 1;int step = src.step;int  p2, p3, p4, p5, p6, p7, p8, p9;uchar* img;bool ifEnd;cv::Mat tmpimg;int dir[4] = { -step, step, 1, -1 };while (1){//分四个子迭代过程,分别对应北,南,东,西四个边界点的情况ifEnd = false;for (n = 0; n < 4; n++){dst.copyTo(tmpimg);img = tmpimg.data;for (i = 1; i < height; i++){img += step;for (j = 1; j<width; j++){uchar* p = img + j;//如果p点是背景点或者且为方向边界点,依次为北南东西,继续循环if (p[0] == 0 || p[dir[n]]>0) continue;p2 = p[-step]>0 ? 1 : 0;p3 = p[-step + 1]>0 ? 1 : 0;p4 = p[1]>0 ? 1 : 0;p5 = p[step + 1]>0 ? 1 : 0;p6 = p[step]>0 ? 1 : 0;p7 = p[step - 1]>0 ? 1 : 0;p8 = p[-1]>0 ? 1 : 0;p9 = p[-step - 1]>0 ? 1 : 0;//8 simple判定int is8simple = 1;if (p2 == 0 && p6 == 0){if ((p9 == 1 || p8 == 1 || p7 == 1) && (p3 == 1 || p4 == 1 || p5 == 1))is8simple = 0;}if (p4 == 0 && p8 == 0){if ((p9 == 1 || p2 == 1 || p3 == 1) && (p5 == 1 || p6 == 1 || p7 == 1))is8simple = 0;}if (p8 == 0 && p2 == 0){if (p9 == 1 && (p3 == 1 || p4 == 1 || p5 == 1 || p6 == 1 || p7 == 1))is8simple = 0;}if (p4 == 0 && p2 == 0){if (p3 == 1 && (p5 == 1 || p6 == 1 || p7 == 1 || p8 == 1 || p9 == 1))is8simple = 0;}if (p8 == 0 && p6 == 0){if (p7 == 1 && (p3 == 9 || p2 == 1 || p3 == 1 || p4 == 1 || p5 == 1))is8simple = 0;}if (p4 == 0 && p6 == 0){if (p5 == 1 && (p7 == 1 || p8 == 1 || p9 == 1 || p2 == 1 || p3 == 1))is8simple = 0;}int adjsum;adjsum = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;//判断是否是邻接点或孤立点,0,1分别对于那个孤立点和端点if (adjsum != 1 && adjsum != 0 && is8simple == 1){dst.at<uchar>(i, j) = 0; //满足删除条件,设置当前像素为0ifEnd = true;}}}}if (!ifEnd) break;}return dst;
}

调用:

cv::Mat thiningMat = thining_img(tmpMat, cv::Rect(0, 0, tmpMat.cols, tmpMat.rows), 1); //细化

4.3 两图重叠看效果

(两个矩阵逐元素加权求和)

0.3和0.7为图片的权重,两数之和必须为1。

    cv::Mat BowCurveMat_;cv::addWeighted(src, 0.3, tmpMat, 0.7, 0, BowCurveMat_); //重叠看效果if (debug) cv::imshow("重叠看效果", BowCurveMat); //显示重叠效果

4.4 锐化

法一:

函数:

cv::Mat ImageProcessing::Sharpen(cv::Mat input, int percent, int type)
{cv::Mat result;cv::Mat s = input.clone();cv::Mat kernel;switch (type){case 0:kernel = (cv::Mat_<int>(3, 3) <<0, -1, 0,-1, 4, -1,0, -1, 0);case 1:kernel = (cv::Mat_<int>(3, 3) <<-1, -1, -1,-1, 8, -1,-1, -1, -1);default:kernel = (cv::Mat_<int>(3, 3) <<0, -1, 0,-1, 4, -1,0, -1, 0);}filter2D(s, s, s.depth(), kernel);result = input + s * 0.01 * percent;return result;
}

调用:

src = pd.Sharpen(src, 500, 0);

法二:(src为原图)

 cv::Mat h1_kernel = (cv::Mat_<char>(3, 3) << -1, -1, -1, -1, 8, -1, -1, -1, -1);cv::Mat h2_kernel = (cv::Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);cv::Mat h1_result, h2_result;cv::filter2D(src, h1_result, CV_32F, h1_kernel);cv::filter2D(src, h2_result, CV_32F, h2_kernel);cv::convertScaleAbs(h1_result, h1_result);cv::convertScaleAbs(h2_result, h2_result);cv::imshow("h1_result", h1_result);cv::imshow("h2_result", h2_result);

5、将细化后的黑白图像中,白色点存入ArcLst后按Y排序

 std::vector<std::vector<cv::Point>> contours_t;std::vector<cv::Vec4i> hierarchy_t;std::vector<std::vector<cv::Point>>::iterator k_t;    //迭代器,访问容器数据cv::findContours(thiningMat, contours_t, hierarchy_t, cv::RETR_EXTERNAL, CV_RETR_LIST); //查找外轮廓,压缩存储轮廓点int  circular_count_t = 0;if (contours_t.size() <= 0){if (debug) printf(" 查找所有轮廓为空! 查找失败!\n");return false;}std::vector<cv::Point2i> ArcLst;int  count_t = 0;for (k_t = contours_t.begin(); k_t != contours_t.end(); ++k_t){std::vector<cv::Point> curContours = *k_t;count_t += curContours.size();if (curContours.size() < 50) continue;for (int i = 0; i < curContours.size(); i++){cv::Point2i pt = cv::Point2f(curContours[i].x, curContours[i].y);int findsame = 0;for (int j = 0; j < ArcLst.size(); j++){cv::Point2i tmp = ArcLst.at(j);if ((pt.x == tmp.x) && (pt.y == tmp.y)){findsame = 1;break;}}if (findsame == 0)  ArcLst.push_back(pt); //图像上的所有点入队列}}if (ArcLst.size() <= 0){if (debug) printf("轮廓中点数大于50的集合为空! 查找圆心失败\n");return false;}std::sort(ArcLst.begin(), ArcLst.end(), compareInterval); //按Y排序for (int i = 0; i < ArcLst.size(); i++){if (debug) printf("[%d, %d] \n", ArcLst.at(i).x, ArcLst.at(i).y);}//if (debug)//{// cv::Mat ArcMat = cv::Mat::zeros(thiningMat.size(), CV_8UC1);  //绘制ArcLst(测试ArcLst中的点是否找对了)//   for (int i = 0; i < ArcLst.size(); i++)// {//     cv::Point P = cv::Point(ArcLst.at(i).x, ArcLst.at(i).y);//     ArcMat.at<uchar>(P) = 255;// }// cv::imshow("ArcMat", ArcMat);//   cv::waitKey(2);//}

按Y排序函数:

//排序用
bool compareInterval(cv::Point2i i1, cv::Point2i i2)
{return (i1.y < i2.y);
}

6、使点集 中的点重排(按x坐标或y坐标)

函数:

//对点的坐标按x从小到大排序,若x值相同则按y从小到大排序
bool compareValue_x(const cv::Point3f& pt1, const cv::Point3f& pt2)
{if (pt1.x != pt2.x)return pt1.x < pt2.x;elsereturn pt1.y < pt2.y;
}//对点的坐标按y从小到大排序,若y值相同则按x从小到大排序
bool compareValue_y(const cv::Point3f& pt1, const cv::Point3f& pt2)
{if (pt1.y != pt2.y)return pt1.y < pt2.y;elsereturn pt1.x < pt2.x;
}

调用:

 //按照机械臂坐标下的x值排序std::sort(VisionToRbt_Lst.begin(), VisionToRbt_Lst.end(), compareValue_x);printf("\n\n按照机械臂坐标下的x值排序---------------------------------------------------------\n");for (int i = 1; i < VisionToRbt_Lst.size(); i++){curpos = VisionToRbt_Lst.at(i);printf("圆弧上的点按照机械臂坐标下的X值排序----第%d个点坐标:%f ,%f, %f \n", i, curpos.x, curpos.y, curpos.z);}//按照机械臂坐标下的y值排序std::sort(VisionToRbt_Lst.begin(), VisionToRbt_Lst.end(), compareValue_y);

7、判图是否为全黑

法一:

cv::countNonZero():返回灰度值不为0的像素个数,可用来判断图像是否全黑

 //一个不为0的像素都没有,即全黑时,直接返回falseint iVal255 = cv::countNonZero(grayMat);if (!iVal255) return false;

法二:

在查找完轮廓后,判断轮廓数量是否为0。没有轮廓则认为图像为全黑。

if (contours.size() <= 0)//图为全黑时{cout << "contours.size() <= 0";return false;}

8、循环测试图像

 //循环测试图像for (int i = 2431; i <= 2556; i++){cv::Mat dstMat;//pd.m_picNum = i;//string path = cv::format("E:\\qtproject\\LK_CJY\\LK\\QtApp_Cylinder\\win64_exe\\release\\Log\\testIMG\\%d.bmp", i);string path = cv::format("E:\\qtproject\\LK_CJY\\LK\\QtApp_Cylinder\\win64_exe\\release\\Log\\testIMG\\%d.png", i);//string path = cv::format("E:\\qtproject\\LK_CJY\\LK\\QtApp_Cylinder\\win64_exe\\release\\Log\\sameIMG\\MV-CA013-A0GM (G70951075)\\%d.png", i);//string path = cv::format("E:\\qtproject\\LK_CJY\\LK\\QtApp_Cylinder\\win64_exe\\release\\Log\\类型IMG\\%d.bmp", i);src = cv::imread(path);cv::Mat  tmpMat = cv::Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0, 0, 0));//cv::threshold(tmpMat, tmpMat, 254, 255, CV_THRESH_BINARY);top = 0;bottom = 0;int  mid_Y;pd.Find_Mid_Y(src, mid_Y);//pd.cutTop_Mid_Ex_debug(src, mid_Y, top, bottom, 150, dstMat, 80, true);//断开pd.Find_NoGap_Location(src, mid_Y, top, bottom, 200, dstMat, 80, true);//连接string SAVEpath = cv::format("E:\\qtproject\\LK_CJY\\LK\\QtApp_Cylinder\\win64_exe\\release\\Log\\resultIMG\\%d_relust.bmp", i);cv::imwrite(SAVEpath, dstMat);printf("\n main---------**---------top=%d, bottom=%d \n", top, bottom);printf("\n\n\n\n-------------------------------当前图片为: %d.bmp---------------------------------------------\n", i);//cv::waitKey(300);}

9、打印区域内的像素灰度值

//过滤已得的T&B是否真的有效,还是只是光虚
bool ImageProcessing::Final_Filtration(cv::Mat src, int &top, int &bottom, int &left, int &right, bool debug)
{bool rt = false;int dis = 8;cv::Mat  grayMat;if (src.type() != CV_8UC1)cv::cvtColor(src, grayMat, cv::COLOR_BGR2GRAY);elsesrc.copyTo(grayMat);for (int row = top; row <= bottom; row++){if (debug) printf("第%d行:", row);for (int col = left - dis; col <= right + dis; col++){int pv = grayMat.at<uchar>(row, col);if (debug) printf("%4d", pv);}if (debug) printf("\n");}if (debug) printf("\n");cv::Mat thresholdMat;cv::threshold(grayMat, thresholdMat, 35, 255, CV_THRESH_BINARY);if (debug) printf("阈值后:\n");for (int row = top; row <= bottom; row++){if (debug) printf("第%d行:", row);for (int col = left - dis; col <= right + dis; col++){int pv = thresholdMat.at<uchar>(row, col);if (debug) printf("%4d", pv);}if (debug) printf("\n");}if (debug) printf("\n");for (int row = top; row <= bottom; row++){int col_WhiteDotNum = 0;int colValue = getRowSum(thresholdMat, row, col_WhiteDotNum);if (debug) printf("第%d行白点个数:%d \n", row, col_WhiteDotNum);if (col_WhiteDotNum == 0) rt = true;//有存在无白点的情况则表示断开有效}return rt;
}

打印区域内的像素灰度值 + 找出最大及最小灰度值 + 根据max灰度值自适应阈值:

bool ImageProcessing::find_maxGrayValue_indexEx(cv::Mat src, int top, int bottom, int left, int right, int & maxGrayValue, int & minGrayValue, bool debug)
{bool rt = false;int dis = 0;//往外扩25cv::Mat  grayMat;if (src.type() != CV_8UC1)cv::cvtColor(src, grayMat, cv::COLOR_BGR2GRAY);elsesrc.copyTo(grayMat);bool beginFlag = true;if (beginFlag){if (debug) printf("第   列:");for (int col = left - dis; col <= right + dis; col++){if (debug) printf("%4d", col);}beginFlag = false;}//int maxGrayValue = 0;cv::Point2f maxGrayValue_index = cv::Point2f(top, left);cv::Point2f minGrayValue_index = cv::Point2f(top, left);for (int row = top; row <= bottom; row++){if (debug) printf("第%d行:", row);int minX = left - dis;int maxX = right + dis;if (minX < 0) minX = 0;if (maxX >src.cols) minX = src.cols;for (int col = minX; col <= maxX; col++){int pv = grayMat.at<uchar>(row, col);if (debug) printf("%4d", pv);if (pv > maxGrayValue){maxGrayValue = pv;maxGrayValue_index = cv::Point2f(col, row);}if (pv < minGrayValue){minGrayValue = pv;minGrayValue_index = cv::Point2f(col, row);}}if (debug) printf("\n");}if (debug) printf("maxGrayValue = %d , maxGrayValue_index = [%f, %f]\n", maxGrayValue, maxGrayValue_index.x, maxGrayValue_index.y);if (debug) printf("minGrayValue = %d , minGrayValue_index = [%f, %f]\n", minGrayValue, minGrayValue_index.x, minGrayValue_index.y);if (debug) printf("\n");if (debug) printf("\n");if (debug) printf("\n");//cv::Mat thresholdMat;//cv::threshold(grayMat, thresholdMat, maxGrayValue - 5, 255, CV_THRESH_BINARY);//if (debug) printf("阈值后:\n");//for (int row = top; row <= bottom; row++)//{//  if (debug) printf("第%d行:", row);// for (int col = left - dis; col <= right + dis; col++)// {//     int pv = thresholdMat.at<uchar>(row, col);//     if (debug) printf("%4d", pv);//   }// if (debug) printf("\n");//}//if (debug) printf("\n");//for (int row = top; row <= bottom; row++)//{//    int col_WhiteDotNum = 0;// int colValue = getRowSum(thresholdMat, row, col_WhiteDotNum);//    //if (debug) printf("第%d行白点个数:%d \n", row, col_WhiteDotNum);// if (col_WhiteDotNum == 0) rt = true;//有存在无白点的情况则表示断开有效//}return rt;
}

调用示例:

 int dis = 10;int  maxGrayValue;int  minGrayValue;find_maxGrayValue_indexEx(grayMat, 0, grayMat.rows, 0 + dis, grayMat.cols - dis, maxGrayValue, minGrayValue, debug);

10、检测最接近给定坐标的光斑直径

//检测光斑直径
float ImageProcessing::detect_spot_Diameter(cv::Mat imgOriginal, float y_Origin, float x_Origin, bool debug)
{cv::Mat img;//可视化光斑轮廓位置的画布imgOriginal.copyTo(img);float spot_Diameter = 0;//光斑直径vector<vector<cv::Point>> contours;       //轮廓组vector<cv::Vec4i> hierarchy;//寻找包裹轮廓的最小圆vector<cv::Point2f>centers(contours.size());//圆心vector<float>radius(contours.size());//半径cv::Mat imgBlur;imgBlur = preProcessing(imgOriginal, 100, debug);findContours(imgBlur, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);   //检测轮廓for (int i = 0; i < contours.size(); i++){//寻找并绘制最小圆cv::Point2f centers_;float  radius_;cv::minEnclosingCircle(contours[i], centers_, radius_);if(debug) circle(img, centers_, radius_, cv::Scalar(115, 33, 221), 2);centers.push_back(centers_);radius.push_back(radius_);}int resultIndex = 0;cv::Point2f cur_centers = centers.at(0);float minDistance = sqrt((x_Origin - cur_centers.x)*(x_Origin - cur_centers.x) + (y_Origin - cur_centers.y)*(y_Origin - cur_centers.y));if (centers.size() > 1)//防崩溃{for (int i = 1; i < centers.size(); i++){cur_centers = centers.at(i);float curDistance;curDistance = sqrt((x_Origin - cur_centers.x)*(x_Origin - cur_centers.x) + (y_Origin - cur_centers.y)*(y_Origin - cur_centers.y));if (minDistance > curDistance){minDistance = curDistance;resultIndex = i;}}}spot_Diameter = radius.at(resultIndex);if (debug){for (int i = 0; i < centers.size(); i++){printf("检测到第 %d 个圆,centers=【%.2f,%.2f】  radius=%f \n", i + 1, centers.at(i).x, centers.at(i).y, radius.at(i));}circle(img, centers[resultIndex], spot_Diameter, cv::Scalar(255,0,0), 1);//圈circle(img, centers[resultIndex], 1, cv::Scalar(0, 255, 255), cv::FILLED);//点cv::imshow("img可视化检测到的所有有效光斑", img);printf("最终得到第 %d 个圆为结果,centers=【%.2f,%.2f】  radius=%f  输出直径为:%f\n", resultIndex+1, centers.at(resultIndex).x, centers.at(resultIndex).y, radius.at(resultIndex), spot_Diameter * 2);}return spot_Diameter * 2;
}

11、打印每行白点个数,并返回每行像素和

函数:

int ImageProcessing::getRowSum(cv::Mat src, int row, int & WhiteDotNum)
{int sum = 0;int height = src.rows;int width = src.cols;WhiteDotNum = 0;for (int i = 1; i < width; i++){int tmpV = src.at <uchar>(row, i);sum += tmpV;if (tmpV>10)WhiteDotNum++;}return sum;
}

调用:

 int  col_WhiteDotNum = 0;for (int i = 0; i < tmpMat.rows; i++){int colValue = getRowSum(tmpMat, i, col_WhiteDotNum);if (debug) printf("第 %d 行 白点个数col_WhiteDotNum =%d \n", i, col_WhiteDotNum);}

12、打印耗时

 int time_start = clock();int time_end = clock();//要计算最终时间时time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start); 

13、造黑图测试

     //造黑图测试cv::Mat m = cv::Mat::zeros(imgOriginal.size(), CV_8UC1);cv::imshow("m", m);if (!pd.M_LookDown(m, splice_i_mf, splice_o_mf, resPoint, canvas, true)){cout << "黑图" << endl;}cv::waitKey();

14、提取骨干点集(同一行只保存一个白点,即最高亮处的中心点)

(所根据的图像tmpMat阈值完且删除最小连通域后的图像

纯代码,提取骨干点集和骨干处像素部分没有封装成函数版本: 

 //提取骨干点集//---------------------------------------------------------- 封装成函数部分 开始int left = 100;int right = tmpMat.cols - 100;std::vector<cv::Point> bright_point;//max点std::vector<int> bright_value;//max像素值//int maxGrayValue = 0;//bool maxGray_flag = false;bool lianxu = false;int firstX;             //找maxCol的区域宽度首次定位int maxCol_dis = 50; //找maxCol的区域宽度int maxCol_l;         //找maxCol的区域宽度左int maxCol_r;            //找maxCol的区域宽度右bool lastPoint_valid = false;//上一个激光点是否有效cv::Point prePoint;bool firstMax = false;//第一个有效的点是否已经出现for (int i = 0; i < tmpMat.rows; i++){int tpvMax = 0;bool flag = false;cv::Point tpvMax_p = cv::Point(0, 0);int maxCol = 0;//bool maxCol_flag = false;//int black = 0;if (bright_point.size() >= 1)//防崩溃{if (bright_point.at(bright_point.size() - 1) != cv::Point(0, 0)){firstMax = true;prePoint = bright_point.at(bright_point.size() - 1);//更新左右搜寻的左右边界int middleCol = prePoint.x;//上一个有效激光点的xif (middleCol - maxCol_dis > 0) maxCol_l = middleCol - maxCol_dis;else maxCol_l = 0;if (middleCol + maxCol_dis < tmpMat.cols) maxCol_r = middleCol + maxCol_dis;else maxCol_r = tmpMat.cols;}}if (i == 0 || firstMax == false)//if (i == 0){for (int col = 0; col <= tmpMat.cols; col++)//先找出每行max{int tpv = tmpMat.at<uchar>(i, col);if (tpvMax < tpv){tpvMax = tpv;firstX = col;maxCol = col;//记下第一个max的x//maxCol_flag = true;}//if (tpv == 0 && tmpMat.at<uchar>(i, col + 1) == 0 && tmpMat.at<uchar>(i, col + 2) == 0) break;//有找到连续三个黑点则提前break}if (firstX - maxCol_dis > 0) maxCol_l = firstX - maxCol_dis;else maxCol_l = 0;if (firstX + maxCol_dis < tmpMat.cols) maxCol_r = firstX + maxCol_dis;else maxCol_r = tmpMat.cols;//if (bright_point.size() >= 1)//防崩溃//{//   if (bright_point.at(bright_point.size() - 1) != cv::Point(0, 0))// {//     firstMax = true;// }//}}else{if (i == 434) printf("''''''''''''''''''maxCol_l=%d   tpvmaxCol_r= %d'''''''''''''''''''''''''''''qqqq-%d \n", maxCol_l, maxCol_r, i);for (int col = maxCol_l; col <= maxCol_r; col++)//先找出每行max{int tpv = tmpMat.at<uchar>(i, col);if (i == 434){printf("''''''''''''''''''tpvMax=%d   tpv=%d'''''''''''''''''''''''''''''qqqq-%d \n", tpvMax, tpv, i);}if (tpvMax < tpv){tpvMax = tpv;maxCol = col;//记下第一个max的x//maxCol_flag = true;}//if (tpv == 0 && tmpMat.at<uchar>(i, col + 1) == 0 && tmpMat.at<uchar>(i, col + 2) == 0) break;//有找到连续三个黑点则提前break}if (bright_point.size() >= 1)//防崩溃{if (bright_point.at(bright_point.size() - 1) == cv::Point(0, 0))//若上一个点不是有效的激光点{lastPoint_valid = false;}else//若上一个点是有效的激光点{lastPoint_valid = true;}}}if (tpvMax == 0){if (debug) std::cout << "aaaaaaaaaaaaaaaaaaaaaaaaaa  -- " << i << std::endl;bright_point.push_back(cv::Point(0, 0));bright_value.push_back(0);continue;}if (lastPoint_valid == false)//未开始找到有效点时{left = maxCol;//左边界得到right = maxCol;//int left_t = maxCol; //int   right_t = maxCol;lianxu = false;for (int col = maxCol + 1; col <= maxCol + 100; col++)//找右边界{int tpv = tmpMat.at<uchar>(i, col);if (tmpMat.at<uchar>(i, col - 1) == tpvMax && tpv == tpvMax)//判断连续{lianxu = true;}else if (tmpMat.at<uchar>(i, col - 1) == tpvMax && tpv < tpvMax){if (lianxu)//右边界{right = col;flag = true;break;}lianxu = false;}}}//else if (lastPoint_valid == true)//找到有效点后,后面开始每个点都寻找与上一个有效点最近的点else//找到有效点后,后面开始每个点都寻找与上一个有效点最近的点{left = 0;//左边界right = 0;int middleCol = prePoint.x;//上一个有效激光点的xfor (int col = middleCol; col >= 1; col--)//先找到左边界(>=1是为了防崩溃){int tpv = tmpMat.at<uchar>(i, col);if (tmpMat.at<uchar>(i, col - 1) != tpvMax && tpv == tpvMax){left = col;break;}}if (left == 0){for (int col = middleCol; col < tmpMat.cols; col++)//先找到左边界(前面没找到则此处再找一遍){int tpv = tmpMat.at<uchar>(i, col);if (tmpMat.at<uchar>(i, col - 1) != tpvMax && tpv == tpvMax){left = col;break;}}}//开始找右边界right = left;lianxu = false;for (int col = left + 1; col <= left + 100; col++)//找右边界{int tpv = tmpMat.at<uchar>(i, col);if (tmpMat.at<uchar>(i, col - 1) == tpvMax && tpv == tpvMax)//判断连续{lianxu = true;}else if (tmpMat.at<uchar>(i, col - 1) == tpvMax && tpv < tpvMax){if (lianxu)//右边界{right = col;flag = true;break;}lianxu = false;}}}tpvMax_p.x = left + (right - left) / 2;tpvMax_p.y = i;bright_value.push_back(tmpMat.at<uchar>(tpvMax_p.y, tpvMax_p.x));bright_point.push_back(tpvMax_p);cv::Point curPoint = bright_point.at(bright_point.size() - 1);if (debug) printf("第%d 行, 【%d, %d】    left= %d   right= %d   \n", i, curPoint.x, curPoint.y, left, right);}//---------------------------------------------------------- 封装成函数部分 结束//得到趋势List ==》trend----下面的一段注释作用//vector<int> trend;//趋势(x走向)(当前减去前一个)//for (int i = 0; i < bright_point.size(); i++)//{//   if (i == 0) trend.push_back(1);// else//  {//     int cur_trend = bright_point.at(i).x - bright_point.at(i - 1).x;//     if (cur_trend == 0)//     {//         trend.push_back(trend.at(trend.size() - 1));//(当前无变化则延续上一个有效趋势)//     }//     else//      {//         trend.push_back(cur_trend);//       }// }//}//if (debug)//{//   printf("骨干点集更新前:\n");//    for (int i = 0; i < bright_point.size(); i++)//   {//     cv::Point curPoint = bright_point.at(i);//     int curGray = bright_value.at(i);//        //printf("第%d 行, 【%d, %d】 灰度值:%d  趋势:%d  \n", i, curPoint.x, curPoint.y, curGray, trend.at(i));//       printf("第%d 行, 【%d, %d】 灰度值:%d  x趋势:%d  \n", i, curPoint.x, curPoint.y, bright_value.at(i), trend.at(i));// }//}//把直激光上短的,因光线弱而虚掉的地方填补上----下面的一段注释作用//int a = 0;//int black = 0;//for (int i = 10; i < bright_point.size() - 10; i++)//把直激光上短的,因光线弱而虚掉的地方填补上//{// cv::Point curPoint = bright_point.at(i);// int curGray = bright_value.at(i);//    if (bright_value.at(i - 1) != 0 && curGray == 0)//   {//     a++;//    }// else if (bright_value.at(i - 1) == 0 && curGray == 0)// {//     a++;//    }// else//  {//     black = a;//       a = 0;//   }// if (black <= 5)//   {//     if (abs(curPoint.x - bright_point.at(i - black - 1).x) <= 4)//      {//         for (int j = i - black; j < i; j++)//         {//             bright_point[j].x = curPoint.x;//          }//     }//     black = 0;//   }//}//if (debug)//{//   printf("骨干点集更新后(把直激光上短的,因光线弱而虚掉的地方都填补上后):\n");//  for (int i = 0; i < bright_point.size(); i++)//   {//     cv::Point curPoint = bright_point.at(i);//     int curGray = bright_value.at(i);//        printf("第%d 行, 【%d, %d】 灰度值:%d \n", i, curPoint.x, curPoint.y, curGray);// }//}//可视化骨干点集cv::Mat newArcMat = cv::Mat::zeros(tmpMat.size(), CV_8UC1);  //绘制 调试for (int i = 0; i < bright_point.size(); i++) //调试{cv::Point P = cv::Point(bright_point.at(i).x, bright_point.at(i).y);newArcMat.at<uchar>(cv::Point(bright_point.at(i).x, bright_point.at(i).y)) = 255;}cv::Mat  BowCurveMat;cv::Mat imgRGB;if (newArcMat.type() != CV_8UC1)cvtColor(newArcMat, imgRGB, cv::COLOR_RGB2GRAY);else newArcMat.copyTo(imgRGB);cv::addWeighted(tmpMat, 0.3, imgRGB, 0.7, 0, BowCurveMat); //重叠看效果

提取骨干点集和骨干处像素部分 已封装成函数版本: 

函数声明:

 //提取骨干点集std::vector<cv::Point> extrectBackbone(cv::Mat tmpMat, std::vector<int> &bright_value, bool debug = false);

函数定义:

//提取骨干点集
vector<cv::Point> ImageProcessing::extrectBackbone(cv::Mat tmpMat, std::vector<int> &bright_value, bool debug)
{if (debug) printf("------------------------------ 提取骨干点集函数 extrectBackbone 开始 !   \n\n");if (tmpMat.type() != CV_8UC1)cv::cvtColor(tmpMat, tmpMat, cv::COLOR_BGR2GRAY);int left = 100;int right = tmpMat.cols - 100;std::vector<cv::Point> bright_point;//max点//std::vector<int> bright_value;//max像素值//int maxGrayValue = 0;//bool maxGray_flag = false;bool lianxu = false;int firstX;                //找maxCol的区域宽度首次定位int maxCol_dis = 50; //找maxCol的区域宽度int maxCol_l;         //找maxCol的区域宽度左int maxCol_r;            //找maxCol的区域宽度右bool lastPoint_valid = false;//上一个激光点是否有效cv::Point prePoint;bool firstMax = false;//第一个有效的点是否已经出现for (int i = 0; i < tmpMat.rows; i++){int tpvMax = 0;bool flag = false;cv::Point tpvMax_p = cv::Point(0, 0);int maxCol = 0;//bool maxCol_flag = false;//int black = 0;if (bright_point.size() >= 1)//防崩溃{if (bright_point.at(bright_point.size() - 1) != cv::Point(0, 0)){firstMax = true;prePoint = bright_point.at(bright_point.size() - 1);if (debug) printf("prePoint[%d, %d] \n", prePoint.x, prePoint.y);//更新左右搜寻的左右边界int middleCol = prePoint.x;//上一个有效激光点的xif (middleCol - maxCol_dis > 0) maxCol_l = middleCol - maxCol_dis;else maxCol_l = 0;if (middleCol + maxCol_dis < tmpMat.cols) maxCol_r = middleCol + maxCol_dis;else maxCol_r = tmpMat.cols;}}if (i == 0 || firstMax == false)//if (i == 0){for (int col = 0; col <= tmpMat.cols; col++)//先找出每行max{int tpv = tmpMat.at<uchar>(i, col);if (tpvMax < tpv){tpvMax = tpv;firstX = col;maxCol = col;//记下第一个max的x//maxCol_flag = true;}//if (tpv == 0 && tmpMat.at<uchar>(i, col + 1) == 0 && tmpMat.at<uchar>(i, col + 2) == 0) break;//有找到连续三个黑点则提前break}if (firstX - maxCol_dis > 0) maxCol_l = firstX - maxCol_dis;else maxCol_l = 0;if (firstX + maxCol_dis < tmpMat.cols) maxCol_r = firstX + maxCol_dis;else maxCol_r = tmpMat.cols;//if (bright_point.size() >= 1)//防崩溃//{//    if (bright_point.at(bright_point.size() - 1) != cv::Point(0, 0))// {//     firstMax = true;// }//}}else{//if (debug) printf("''''''''''''''''''maxCol_l=%d   tpvmaxCol_r= %d'''''''''''''''''''''''''''''qqqq-%d \n", maxCol_l, maxCol_r, i);for (int col = maxCol_l; col <= maxCol_r; col++)//先找出每行max{int tpv = tmpMat.at<uchar>(i, col);//if (debug)//{// printf("''''''''''''''''''tpvMax=%d   tpv=%d'''''''''''''''''''''''''''''qqqq-%d \n", tpvMax, tpv, i);//}if (tpvMax < tpv){tpvMax = tpv;maxCol = col;//记下第一个max的x//maxCol_flag = true;}//if (tpv == 0 && tmpMat.at<uchar>(i, col + 1) == 0 && tmpMat.at<uchar>(i, col + 2) == 0) break;//有找到连续三个黑点则提前break}if (bright_point.size() >= 1)//防崩溃{if (bright_point.at(bright_point.size() - 1) == cv::Point(0, 0))//若上一个点不是有效的激光点{lastPoint_valid = false;}else//若上一个点是有效的激光点{lastPoint_valid = true;}}}if (tpvMax == 0){if (debug) printf("aaaaaaaaaaaaaaaaaaaaaaaaaa 最大像素值=0!!!  -- %d      left= %d  right= %d   \n", i, left, right);bright_point.push_back(cv::Point(0, 0));bright_value.push_back(0);firstMax = false;continue;}if (debug) printf("   tpvMax= %d   maxCol= %d   \n", tpvMax, maxCol);if (lastPoint_valid == false)//未开始找到有效点时{left = maxCol;//左边界得到right = maxCol;//int left_t = maxCol; //int right_t = maxCol;lianxu = false;for (int col = maxCol + 1; col <= maxCol + 100; col++)//找右边界{int tpv = tmpMat.at<uchar>(i, col);if (tmpMat.at<uchar>(i, col - 1) == tpvMax && tpv == tpvMax)//判断连续{lianxu = true;}else if (tmpMat.at<uchar>(i, col - 1) == tpvMax && tpv < tpvMax){if (lianxu)//右边界{right = col;flag = true;break;}lianxu = false;}}}//else if (lastPoint_valid == true)//找到有效点后,后面开始每个点都寻找与上一个有效点最近的点else//找到有效点后,后面开始每个点都寻找与上一个有效点最近的点{left = 0;//左边界right = 0;int middleCol = prePoint.x;//上一个有效激光点的xif (debug) printf("prePoint[%d, %d]    middleCol=%d \n", prePoint.x, prePoint.y, middleCol);int stopDis = 30;int stop;if (middleCol > stopDis) stop = middleCol - stopDis;else stop = 1;for (int col = middleCol; col >= stop; col--)//先找到左边界(>=1是为了防崩溃){int tpv = tmpMat.at<uchar>(i, col);if (tmpMat.at<uchar>(i, col - 1) != tpvMax && tpv == tpvMax){left = col;break;}}if (left == 0){for (int col = middleCol; col < tmpMat.cols; col++)//先找到左边界(前面没找到则此处再找一遍){int tpv = tmpMat.at<uchar>(i, col);if (tmpMat.at<uchar>(i, col - 1) != tpvMax && tpv == tpvMax){left = col;break;}}}//开始找右边界right = left;lianxu = false;for (int col = left + 1; col <= left + 100; col++)//找右边界{int tpv = tmpMat.at<uchar>(i, col);if (tmpMat.at<uchar>(i, col - 1) == tpvMax && tpv == tpvMax)//判断连续{lianxu = true;}else if (tmpMat.at<uchar>(i, col - 1) == tpvMax && tpv < tpvMax){if (lianxu)//右边界{right = col;flag = true;break;}lianxu = false;}}}tpvMax_p.x = left + (right - left) / 2;tpvMax_p.y = i;bright_value.push_back(tmpMat.at<uchar>(tpvMax_p.y, tpvMax_p.x));bright_point.push_back(tpvMax_p);cv::Point curPoint = bright_point.at(bright_point.size() - 1);if (debug) printf("第%d 行, 【%d, %d】    left= %d   right= %d   \n", i, curPoint.x, curPoint.y, left, right);}if (debug) printf("------------------------------ 提取骨干点集函数 extrectBackbone 结束!   \n\n");return bright_point;
}

函数调用:

 //提取骨干点集std::vector<cv::Point> bright_point;//max点std::vector<int> bright_value;//max像素值bright_point = extrectBackbone(tmpMat, bright_value, debug);if (debug){printf("骨干点集更新前:\n");for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);printf("第%d 行, 【%d, %d】 灰度值:%d \n", i, curPoint.x, curPoint.y, curGray);}}

可视化骨干点集:

 //可视化骨干点集cv::Mat newArcMat = cv::Mat::zeros(tmpMat.size(), CV_8UC1);  //绘制 调试for (int i = 0; i < bright_point.size(); i++) //调试{cv::Point P = cv::Point(bright_point.at(i).x, bright_point.at(i).y);newArcMat.at<uchar>(cv::Point(bright_point.at(i).x, bright_point.at(i).y)) = 255;}cv::Mat  BowCurveMat;cv::Mat imgRGB;if (newArcMat.type() != CV_8UC1)cvtColor(newArcMat, imgRGB, cv::COLOR_RGB2GRAY);else newArcMat.copyTo(imgRGB);cv::addWeighted(tmpMat, 0.3, imgRGB, 0.7, 0, BowCurveMat); //重叠看效果if (debug) cv::imshow("重叠看效果(初始)", BowCurveMat); //显示重叠效果

15、将直线检测后的所有白点入列(同一行有多个点的话就只保留最右边的点),同时打印x值趋势

 //将直线检测后的所有白点入列===================================================================//if (dst.type() != CV_8UC1)//    cv::cvtColor(dst, dst, cv::COLOR_BGR2GRAY);if (debug) cv::imshow("直线检测", dst);vector<cv::Point> tempPoint;for (int row = 0; row < dst.rows; row++){bool flag = false;for (int col = 0; col < dst.cols; col++){int pv = dst.at<uchar>(row, col);if (pv == 255){cv::Point curP = cv::Point(col, row);tempPoint.push_back(curP);flag = true;//if (debug) printf("pv =  %d   ", pv);}}//if (flag == false)//{//    tempPoint.push_back(cv::Point(0, 0));//}if (tempPoint.size() > 1)//打印tempPoint{if (debug) printf("tempPoint.at(i).x = [%d, %d]   \n", tempPoint.at(tempPoint.size() - 1).x, tempPoint.at(tempPoint.size() - 1).y);}//if (debug) printf("\n");}if (debug) cout << "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk  tempPoint.size()=" << tempPoint.size() << endl;//同一行有多个点的话就只保留最右边的点vector<cv::Point> new_bright_point;for (int i = 0; i < tempPoint.size(); i++){if (i + 1 < tempPoint.size())//防越界{if (tempPoint.at(i).y == 0 || tempPoint.at(i).y != tempPoint.at(i + 1).y){new_bright_point.push_back(tempPoint.at(i));//if (debug) printf("tempPoint.at(%d).x = %d,   %d   \n", i, tempPoint.at(i).x, tempPoint.at(i + 1).x);}}}bright_point = new_bright_point;//更新bright_point//直线检测后的所有白点入列===================================================================vector<int> trend;//趋势(x走向)(当前减去前一个)for (int i = 0; i < bright_point.size(); i++){if (i == 0) trend.push_back(1);else{int cur_trend = bright_point.at(i).x - bright_point.at(i - 1).x;if (cur_trend == 0){trend.push_back(trend.at(trend.size() - 1));//(当前无变化则延续上一个有效趋势)}else{trend.push_back(cur_trend);}}}if (debug){printf("骨干点集更新前:\n");for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);//printf("第%d 行, 【%d, %d】 灰度值:%d  趋势:%d  \n", i, curPoint.x, curPoint.y, curGray, trend.at(i));printf("第%d 行, 【%d, %d】 灰度值:%d  x趋势:%d  \n", i, curPoint.x, curPoint.y, bright_value.at(i), trend.at(i));}}//提取骨干点集//-----------------------------------------------------------------------------------------------------int tolerance = 5;//允许的直线不平滑波动范围长度int pointIndex = 0;int trendNum = 1;int pre_trendNum = 1;std::vector<int> trendNumList;//连续趋势列表std::vector<int> pre_trendNumList;//上一次有效连续趋势的连续数量trendNumList.push_back(0);pre_trendNumList.push_back(0);//得出trendNumList和pre_trendNumList(连续趋势列表 和 上一次有效连续趋势的连续数量)for (int i = 1; i < trend.size(); i++){int cur_trend = trend.at(i);//有变化就归一,重新计算if ((cur_trend > 0 && trend.at(i - 1) < 0) || (cur_trend < 0 && trend.at(i - 1) > 0)){if (trendNum <= tolerance){trendNum = pre_trendNum + trendNum;trendNum++;}else{pre_trendNum = trendNum;trendNum = 1;}}else if ((cur_trend > 0 && trend.at(i - 1) > 0) || (cur_trend < 0 && trend.at(i - 1) < 0)){trendNum++;//变化趋势一样则次数增加;}trendNumList.push_back(trendNum);pre_trendNumList.push_back(pre_trendNum);cv::Point curPoint = bright_point.at(i);if (debug) printf("第%d 行, 【%d, %d】 灰度值:%d  x趋势trend:%d  trendNum:%d  pre_trendNum:%d \n", i, curPoint.x, curPoint.y, bright_value.at(i), trend.at(i), trendNumList.at(i), pre_trendNumList.at(i));//std::printf("第%d 行, 【%d, %d】 灰度值:%d  x趋势:%d  trendNum:%d  pre_trendNum:%d \n", i, curPoint.x, curPoint.y, bright_value.at(i), trend.at(i), trendNum, pre_trendNum);}

16、已有两个点坐标,求对应线段

 cv::Point point3 = cv::Point(0, 0);double line1_b;//最上面一条直线的截距double line1_k;//最上面一条直线的斜率cv::Point line1_point;//最上面一条直线的一个点//if (point2_index > 50)//防崩溃//{//  取point2往前第10个点作为最上面一条直线的一个点//   //line1_point = bright_point.at(point2_index - 50);//  line1_point = bright_point.at(29);//   if (debug) printf("\nline1_point = [%d, %d] \n", line1_point.x, line1_point.y);//}line1_point = bright_point.at(29);if (debug) printf("\nline1_point = [%d, %d] \n", line1_point.x, line1_point.y);cv::circle(canvas, line1_point, 3, cv::Scalar(110, 136, 245), -1, 8, 0);line1_k = (double)(line1_point.y - point2.y) / (double)(line1_point.x - point2.x);line1_b = point2.y - point2.x * line1_k;if (debug) printf("line1_k = %lf \n", line1_k);if (debug) printf("line1_b = %lf \n", line1_b);if (debug) printf("line1_point.y = %d, point2.y=%d , line1_point.x=%d , point2.x=%d \n", line1_point.y, point2.y, line1_point.x, point2.x);//if (debug) cout << line1_k*line1_point.x + line1_b << endl << endl;cv::line(canvas, cv::Point((5 - line1_b) / line1_k, 5), cv::Point((1000 - line1_b) / line1_k, 1000), cv::Scalar(255, 0, 0), 1, cv::LINE_AA, 0);

17、已有直线的斜率和截距,寻找离直线最近的点坐标

 //已有最上面的直线方程,往下延长直线找白点,或是与延长线距离最近的白点double minDis = 100000;for (int i = point2_index + 10; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);double curDis = abs(curPoint.x - (curPoint.y - line1_b) / line1_k);//if (debug) printf("curPoint.y = %d, line1_k =%lf , curPoint.x =%d , line1_b=%lf \n", curPoint.y, line1_k, curPoint.x, line1_b);if (minDis > curDis){minDis = curDis;point3 = curPoint;//if (debug) cout << "minDis = " << minDis << endl;}}//cv::circle(canvas, point3, 3, cv::Scalar(0, 0, 255), -1, 8, 0);//cv::putText(canvas, "3", cv::Point(point3.x - 10, point3.y - 10), cv::FONT_HERSHEY_DUPLEX, 0.75, cv::Scalar(0, 69, 255), 2);//printf("得到的新point3 = [%d, %d]   ------- end\n", point3.x, point3.y);resPoint.push_back(point3);cv::circle(canvas, resPoint.at(2), 3, cv::Scalar(0, 0, 255), -1, 8, 0);cv::putText(canvas, "3", cv::Point(resPoint.at(2).x - 20, resPoint.at(2).y + 15), cv::FONT_HERSHEY_DUPLEX, 0.75, cv::Scalar(0, 69, 255), 2);printf("得到的新point3 = [%d, %d]   ------- end\n", resPoint.at(2).x, resPoint.at(2).y);

18、vector中求众数

函数:

/************ 求数组中的众数 *************/
std::vector<int>  ImageProcessing::majorityElement(vector<int> arr, int  &selectNum, int &count_)
{vector<int> numSet;vector<int> count;vector<int> res;numSet.push_back(arr[0]);count.push_back(1);/*if (arr.size() < 1){res.push_back([]);return;}//return NULL;else */if (arr.size() == 1){res.push_back(arr[0]);return res;}//当数组大小为1时else if (arr.size() == 2){res.push_back(arr[0]);if (arr[0] != arr[1]){res.push_back(arr[1]);}return res;} //当数组大小为2时//当数组大小大于等于三时sort(arr.begin(), arr.end()); //先排序int m = 0;for (int i = 1; i < arr.size(); i++){if (arr[i] != arr[i - 1]) {numSet.push_back(arr[i]);//记录下不重复的值count.push_back(1); //并将次数赋值为1m++;}elsecount[m]++; //当和前值相等时,次数加1}int max = count[0];for (int i = 0; i < count.size(); i++) //求出最大的次数{if (max < count[i])max = count[i];}for (int i = 0; i < count.size(); i++) //输出次数最大的值{if (count[i] == max)res.push_back(numSet[i]);}if (res.size() >= 1){selectNum = res.at(0);count_ = max;}return res;//cout << arr[i] << ' ';
}

调用:

     int  countMax, MaxCountY;//众数,众数的数量majorityElement(endPointY, MaxCountY, countMax);//参数1:传入的 需要求众数的 vectorif (debug) printf("得到的y值(众数) MaxCountY= %d     (众数的数量)countMax=%d  \n\n", MaxCountY, countMax); 

19、传入的图片只截取ROI

函数头:

 bool   cutTop_Mid_Ex_debug0817ROI(cv::Mat src, int start_Y, int &top, int &bottom, int ROI_top, int ROI_bottom, int ROI_left, int ROI_right, int yuzhi, cv::Mat &BowCurveMat_, int length, bool debug = false);//断开

函数:

bool ImageProcessing::cutTop_Mid_Ex_debug0817ROI(cv::Mat src, int start_Y, int & top, int & bottom, int ROI_top, int ROI_bottom, int ROI_left, int ROI_right, int yuzhi, cv::Mat & BowCurveMat_, int length, bool debug)
{bool res;start_Y = (ROI_bottom - ROI_top) / 2;src.copyTo(BowCurveMat_);if (debug) printf("start_Y = %d\n", start_Y);//cv::Mat back = cv::Mat::zeros(imgBlur2.size(), imgBlur2.type());//----------- 提取ROI区域cv::Rect roi(ROI_left, ROI_top, ROI_right - ROI_left, ROI_bottom - ROI_top);cv::Mat imgCrop = src(roi);if (res = cutTop_Mid_Ex_debug0817(imgCrop, start_Y, top, bottom, yuzhi, BowCurveMat_, length, debug) == true){top += ROI_top;bottom += ROI_top;cv::line(BowCurveMat_, cv::Point(600, top), cv::Point(725, top), cv::Scalar(255, 255, 0), 1, cv::LINE_AA, 0); //蓝色cv::line(BowCurveMat_, cv::Point(575, bottom), cv::Point(700, bottom), cv::Scalar(255, 0, 255), 1, cv::LINE_AA, 0); //紫色}return res;
}

例子2:

bool weldJarROI(cv::Mat imgOriginal, splice_in splice_i, splice_out &splice_o, int ROI_top, int ROI_bottom, int ROI_left, int ROI_right, bool debug = false);bool ImageProcessing::weldJarROI(cv::Mat imgOriginal, splice_in splice_i, splice_out & splice_o, int ROI_top, int ROI_bottom, int ROI_left, int ROI_right, bool debug)
{   bool res;//cv::Mat back = cv::Mat::zeros(imgBlur2.size(), imgBlur2.type());//----------- 提取ROI区域cv::Rect roi(ROI_left, ROI_top, ROI_right - ROI_left, ROI_bottom - ROI_top);cv::Mat imgCrop = imgOriginal(roi);res = weldJar(imgCrop, splice_i, splice_o, debug);imgOriginal.copyTo(splice_o.canvas);if (res == true){splice_o.tlPoint.y += ROI_top;splice_o.tlPoint.x += ROI_left;splice_o.trPoint.y += ROI_top;splice_o.trPoint.x += ROI_left;splice_o.tmPoint.y += ROI_top;splice_o.tmPoint.x += ROI_left;cv::circle(splice_o.canvas, splice_o.tlPoint, 3, cv::Scalar(255, 155, 0), -1, 8, 0);cv::putText(splice_o.canvas, "top", cv::Point(splice_o.tlPoint.x - 20, splice_o.tlPoint.y - 35), cv::FONT_HERSHEY_COMPLEX, 0.75, cv::Scalar(255, 155, 0), 2);if (debug) printf("得到的焊缝位置 上端 splice_o.tlPoint = [%d, %d]    \n", splice_o.tlPoint.x, splice_o.tlPoint.y);cv::circle(splice_o.canvas, splice_o.trPoint, 3, cv::Scalar(155, 0, 255), -1, 8, 0);cv::putText(splice_o.canvas, "bottom", cv::Point(splice_o.trPoint.x + 20, splice_o.trPoint.y + 35), cv::FONT_HERSHEY_COMPLEX, 0.75, cv::Scalar(155, 0, 255), 2);if (debug) printf("得到的焊缝位置 下端 splice_o.trPoint = [%d, %d]    \n", splice_o.trPoint.x, splice_o.trPoint.y);cv::circle(splice_o.canvas, splice_o.tmPoint, 1, cv::Scalar(0, 255, 0), -1, 8, 0);cv::putText(splice_o.canvas, "middle", cv::Point(splice_o.tmPoint.x + 5, splice_o.tmPoint.y + 5), cv::FONT_HERSHEY_COMPLEX, 0.5, cv::Scalar(0, 255, 0), 1);if (debug) printf("得到的焊缝位置 中点(焊点) midPoint splice_o.trPoint = [%d, %d]    \n", splice_o.tmPoint.x, splice_o.tmPoint.y);}else{cv::line(splice_o.canvas, cv::Point(60, 60), cv::Point(1000, 1000), cv::Scalar(0, 0, 200), 1, cv::LINE_AA, 0); //红色斜线}if (debug){cv::namedWindow("最终版canvas可视化效果", cv::WINDOW_FULLSCREEN); cv::imshow("最终版canvas可视化效果", splice_o.canvas);}return res;
}

20、vs2015  dll库转成可运行的执行程序(后面可相互随时转换)

将该处从dll改为exe

(每次转换后记得要重新扫描以下:Project--Recan Solution;再编译)

21、得到骨干点集X值的变化趋势,及该变化趋势的 变化趋势

得到骨干点集X值变化趋势

 int trendDis = 2;//计算趋势的间隔vector<int> trend;//趋势(x走向)(当前减去前一个)for (int i = 0; i < bright_point.size(); i++){if (i < trendDis) trend.push_back(0);else{int cur_trend = bright_point.at(i).x - bright_point.at(i - trendDis).x;if (cur_trend == 0){trend.push_back(trend.at(trend.size() - 1));//(当前无变化则延续上一个有效趋势)}else{trend.push_back(cur_trend);}}}

得到骨干点集X值变化趋势 的变化趋势

 int tolerance = 5;//允许的直线不平滑波动范围长度int pointIndex = 0;int trendNum = 1;int pre_trendNum = 1;vector<int> trendNumList;//连续趋势列表vector<int> pre_trendNumList;//上一次有效连续趋势的连续数量trendNumList.push_back(0);pre_trendNumList.push_back(0);//得出trendNumList和pre_trendNumList(连续趋势列表 和 上一次有效连续趋势的连续数量)for (int i = 1; i < trend.size(); i++){int cur_trend = trend.at(i);//有变化就归一,重新计算if ((cur_trend > 0 && trend.at(i - 1) < 0) || (cur_trend < 0 && trend.at(i - 1) > 0)){if (trendNum <= tolerance){trendNum = pre_trendNum + trendNum;trendNum++;}else{pre_trendNum = trendNum;trendNum = 1;}}else if ((cur_trend > 0 && trend.at(i - 1) > 0) || (cur_trend < 0 && trend.at(i - 1) < 0)){trendNum++;//变化趋势一样则次数增加;}trendNumList.push_back(trendNum);pre_trendNumList.push_back(pre_trendNum);cv::Point curPoint = bright_point.at(i);if (debug) printf("第%d 行, 【%d, %d】 灰度值:%d  x趋势trend:%d  trendNum:%d  pre_trendNum:%d \n", i, curPoint.x, curPoint.y, bright_value.at(i), trend.at(i), trendNumList.at(i), pre_trendNumList.at(i));//std::printf("第%d 行, 【%d, %d】 灰度值:%d  x趋势:%d  trendNum:%d  pre_trendNum:%d \n", i, curPoint.x, curPoint.y, bright_value.at(i), trend.at(i), trendNum, pre_trendNum);}

22、将图像 tmpMat 沿中心点逆时针旋转90度

 //----------------------------------------------------------------------------------------------------------- 图像旋转 开始cv::Mat M = cv::getRotationMatrix2D(cv::Point(tmpMat.cols / 2, tmpMat.rows / 2), 90, 1.0);    //获得旋转矩阵 Mdouble cos = abs(M.at<double>(0, 0));  //取绝对值double sin = abs(M.at<double>(0, 1));double nw = cos * tmpMat.cols + sin * tmpMat.rows;      //旋转后图像所占矩形的宽double nh = sin * tmpMat.cols + cos * tmpMat.rows;       //旋转后图像所占矩形的高//更新 新的中心  (将新中心平移到正确位置上)M.at<double>(0, 2) += (nw / 2 - tmpMat.cols / 2);       //将矩形的宽高 加上偏差量  (新M的第一列最后的值)M.at<double>(1, 2) += (nh / 2 - tmpMat.rows / 2);     //将矩形的宽高 加上偏差量  (新M的第二列最后的值)cv::Mat rotateMat;warpAffine(tmpMat, rotateMat, M, cv::Size(nw, nh), cv::INTER_LINEAR, 0, cv::Scalar(255, 255, 0));   //进行旋转rotateMat.copyTo(tmpMat);if (debug) cv::imshow("逆时针旋转90度后tmpMat", tmpMat);//----------------------------------------------------------------------------------------------------------- 图像旋转 结束

23、只画出所有轮廓中最大的那个轮廓

//闭运算cv::Mat close;cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));cv::morphologyEx(imgOriginal, close, cv::MORPH_CLOSE, kernel);//闭操作cv::Mat imgGray;cv::Mat thresholdMat;if (close.type() != CV_8UC1)cv::cvtColor(close, imgGray, cv::COLOR_BGR2GRAY);else close.copyTo(imgGray);//cv::threshold(imgGray, thresholdMat, 240, 255, CV_THRESH_BINARY);cv::adaptiveThreshold(imgGray, thresholdMat, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 51, -18);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); //查找外轮廓,压缩存储轮廓点if (contours.size() <= 0)//图为全黑时{cout << "contours.size() <= 0";return false;}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() < 70) continue;// cv::drawContours(tmpMat, contours, count, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充//}//只画出最大的那个轮廓int maxContou_size = 0;int maxContou_index;for (int i = 0; i < contours.size(); i++){std::vector<cv::Point> curContours = contours.at(i);if (curContours.size() < 70) continue;if (maxContou_size < curContours.size()){maxContou_size = curContours.size();maxContou_index = i;}//cv::drawContours(tmpMat, contours, i, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充}cv::drawContours(tmpMat, contours, maxContou_index, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //只画出最大的那个轮廓if (debug) cv::imshow("删除最小连通域tmpMat", tmpMat);//一个不为0的像素都没有,即全黑时,直接返回falseint iVal255 = cv::countNonZero(tmpMat);if (!iVal255) return 0;//提取骨干点集std::vector<cv::Point> bright_point;//max点std::vector<int> bright_value;//max像素值bright_point = extrectBackbone(tmpMat, bright_value, debug);if (debug){printf("骨干点集更新前:\n");for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);printf("第%d 行, 【%d, %d】 灰度值:%d \n", i, curPoint.x, curPoint.y, curGray);}}可视化骨干点集//cv::Mat newArcMat = cv::Mat::zeros(tmpMat.size(), CV_8UC1);  //绘制 调试//for (int i = 0; i < bright_point.size(); i++) //调试//{//  cv::Point P = cv::Point(bright_point.at(i).x, bright_point.at(i).y);// newArcMat.at<uchar>(cv::Point(bright_point.at(i).x, bright_point.at(i).y)) = 255;//}//cv::Mat  BowCurveMat;//cv::Mat imgRGB;//if (newArcMat.type() != CV_8UC1)//    cvtColor(newArcMat, imgRGB, cv::COLOR_RGB2GRAY);//else newArcMat.copyTo(imgRGB);//cv::addWeighted(tmpMat, 0.3, imgRGB, 0.7, 0, BowCurveMat); //重叠看效果//if (debug) cv::imshow("重叠看效果(初始)", BowCurveMat); //显示重叠效果int a = 0;int black = 0;for (int i = 10; i < bright_point.size() - 10; i++)//把直激光上短的,因光线弱而虚掉的地方填补上{cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);if (bright_value.at(i - 1) != 0 && curGray == 0){a++;}else if (bright_value.at(i - 1) == 0 && curGray == 0){a++;}else{black = a;a = 0;}if (black <= 5){if (abs(curPoint.x - bright_point.at(i - black - 1).x) <= 4){for (int j = i - black; j < i; j++){bright_point[j].x = curPoint.x;}}black = 0;}}if (debug){printf("骨干点集更新后(把直激光上短的,因光线弱而虚掉的地方都填补上后):\n");for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);printf("第%d 行, 【%d, %d】 灰度值:%d \n", i, curPoint.x, curPoint.y, curGray);}}//------------------------------------------------------------ 骨干点集 更新std::vector<cv::Point> tmpPoint;std::vector<int> bright_valueTMP;for (int i = 0; i < bright_point.size(); i++){cv::Point P = cv::Point(bright_point.at(i).x, bright_point.at(i).y);if (P != cv::Point(0, 0)){tmpPoint.push_back(P);bright_valueTMP.push_back(bright_value.at(i));}//------------------------------------- 0927添加 开始else{if (tmpPoint.size() != 0) tmpPoint.push_back(tmpPoint.at(tmpPoint.size() - 1));else tmpPoint.push_back(cv::Point(0, 0));if (bright_valueTMP.size() != 0) bright_valueTMP.push_back(bright_valueTMP.at(bright_valueTMP.size() - 1));else bright_valueTMP.push_back(0);}//------------------------------------- 0927添加 结束}bright_point = tmpPoint;//只保留骨干部分,非骨干部分不再补(0,0)---- 长度不再与图片高度相等bright_value = bright_valueTMP;//for (int i = 0; i < bright_point.size(); i++)//{//   if (debug) printf("只保留骨干部分--骨干点集  bright_point.at(%d) = [%d, %d] \n", i, bright_point.at(i).x, bright_point.at(i).y);//}if (debug) std::cout << std::endl << std::endl;//------------------------------------------------------------ 骨干点集 更新结束//double temp_k;//斜率//std::vector<double> temp_k_List;//斜率集合//for (int i = 0; i < bright_point.size(); i++)//{//  cv::Point curPoint = bright_point.at(i);// int curGray = bright_value.at(i);//    if (i > 2 && i < bright_point.size() - 2)//2是为了防止越界崩溃//   {//     if (bright_point.at(i - 2).x - bright_point.at(i + 2).x == 0)//      {//         temp_k = 0;//      }//     else//      {//         temp_k = (bright_point.at(i - 2).y - bright_point.at(i + 2).y) / (bright_point.at(i - 2).x - bright_point.at(i + 2).x);//        }//     temp_k_List.push_back(temp_k);//    }// else//  {//     temp_k_List.push_back(0);// }// //if (debug) printf("bright_point.at(i - 2).y=%d ,bright_point.at(i + 2).y=%d ,bright_point.at(i - 2).x=%d  , bright_point.at(i + 2).x=%d  \n", bright_point.at(i - 2).y ,bright_point.at(i + 2).y,bright_point.at(i - 2).x , bright_point.at(i + 2).x);//    if (debug) printf("只保留骨干部分--骨干点集  bright_point.at(%d) = [%d, %d]  灰度值:%d     ", i, bright_point.at(i).x, bright_point.at(i).y, curGray);//    if (debug) printf("i = %d   斜率:%.3lf \n", i, temp_k_List.at(i));//    //if (debug) printf("i = %d   斜率:%.3lf \n", i, temp_k);//}double temp_k;//斜率int  col_WhiteDotNum = 0;//白点个数vector<int> col_WhiteDotNum_List;//白点个数集std::vector<double> temp_k_List;//斜率集合for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);斜率//if (i > 2 && i < bright_point.size() - 2)//2是为了防止越界崩溃//{// if (bright_point.at(i - 2).x - bright_point.at(i + 2).x == 0)//  {//     temp_k = 0;//  }// else//  {//     temp_k = (bright_point.at(i - 2).y - bright_point.at(i + 2).y) / (bright_point.at(i - 2).x - bright_point.at(i + 2).x);//    }// temp_k_List.push_back(temp_k);//}//else//{//    temp_k_List.push_back(0);//}//趋势int k_dis = 1;//当前与前面第几个所得到的斜率if (i > k_dis && i < bright_point.size() - 1)//1是为了防止越界崩溃{int curTMP = bright_point.at(i).x - bright_point.at(i - k_dis).x;//趋势temp_k_List.push_back(curTMP);}else{temp_k_List.push_back(0);}int colValue = getRowSum(tmpMat, bright_point.at(i).y, col_WhiteDotNum);col_WhiteDotNum_List.push_back(col_WhiteDotNum);//if (debug) printf("bright_point.at(i - 2).y=%d ,bright_point.at(i + 2).y=%d ,bright_point.at(i - 2).x=%d  , bright_point.at(i + 2).x=%d  \n", bright_point.at(i - 2).y ,bright_point.at(i + 2).y,bright_point.at(i - 2).x , bright_point.at(i + 2).x);if (debug) printf("只保留骨干部分 bright_point.at(%d) = [%d, %d]  灰度值:%d   ", i, bright_point.at(i).x, bright_point.at(i).y, curGray);//if (debug) printf("白点个数col_WhiteDotNum =%d  ", col_WhiteDotNum);if (debug) printf("第%d行 白点个数col_WhiteDotNum =%d-%d  ", bright_point.at(i).y, col_WhiteDotNum, col_WhiteDotNum_List.at(i));if (debug) printf("i= %d  X变化趋势:%.3lf  \n", i, temp_k_List.at(i));//if (debug) printf("i = %d   斜率:%.3lf \n", i, temp_k);}//可视化骨干点集cv::Mat newArcMat = cv::Mat::zeros(tmpMat.size(), CV_8UC1);  //绘制 调试for (int i = 0; i < bright_point.size(); i++) //调试{cv::Point P = cv::Point(bright_point.at(i).x, bright_point.at(i).y);newArcMat.at<uchar>(cv::Point(bright_point.at(i).x, bright_point.at(i).y)) = 255;}cv::Mat  BowCurveMat;cv::Mat imgRGB;if (newArcMat.type() != CV_8UC1)cvtColor(newArcMat, imgRGB, cv::COLOR_RGB2GRAY);else newArcMat.copyTo(imgRGB);//重叠看效果cv::addWeighted(tmpMat, 0.3, imgRGB, 0.7, 0, BowCurveMat);//if (debug) cv::imshow("tmpMat", tmpMat);//if (debug) cv::imshow("imgRGB", imgRGB);if (debug) cv::imshow("_重叠看效果", BowCurveMat); //显示重叠效果

24、提取骨干点集拓展

24.1 获取激光最右点集(骨干点集存入rightmost)

     //提取骨干点集--------- 开始 0928std::vector<cv::Point> bright_point;//max点std::vector<int> bright_value;//max像素值bright_point = extrectBackbone(tmpMat, bright_value, debug);if (debug){printf("骨干点集更新前:\n");for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);printf("第%d 行, 【%d, %d】 灰度值:%d \n", i, curPoint.x, curPoint.y, curGray);}}//提取骨干点集--------- 结束 0928//获得激光最右点集--------- 0928修改版 -----1012注释vector<cv::Point> rightmost;//激光最右点集//int beginCol = bright_point.at(row).y;for (int row = 0; row < tmpMat.rows; row++)//for (int row = bright_point.at(0).y; row < bright_point.at(bright_point.size() - 1).y; row++){for (int col = bright_point.at(row).x; col < tmpMat.cols - 1; col++)//-1是为了防崩溃{int pv = tmpMat.at<uchar>(row, col);if (pv != 0 && tmpMat.at<uchar>(row, col + 1) == 0)//激光最右点入列{rightmost.push_back(cv::Point(col, row));break;}//if (rightmost.size() > 1) beginCol = rightmost.at(0).x - 30;}}

24.2  采用中心点与最右点的中心作为骨干(骨干点集存入rightmost)

     //提取骨干点集--------- 开始 0928std::vector<cv::Point> bright_point;//max点std::vector<int> bright_value;//max像素值bright_point = extrectBackbone(tmpMat, bright_value, debug);if (debug){printf("骨干点集更新前:\n");for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);printf("第%d 行, 【%d, %d】 灰度值:%d \n", i, curPoint.x, curPoint.y, curGray);}}// -----1012修改版   采用中心点与最右点的中心作为骨干vector<cv::Point> rightmost;//激光最右点集//int beginCol = bright_point.at(row).y;for (int row = 0; row < tmpMat.rows; row++)//for (int row = bright_point.at(0).y; row < bright_point.at(bright_point.size() - 1).y; row++){for (int col = bright_point.at(row).x; col < tmpMat.cols - 1; col++)//-1是为了防崩溃{int pv = tmpMat.at<uchar>(row, col);if (pv != 0 && tmpMat.at<uchar>(row, col + 1) == 0)//激光最右点入列{rightmost.push_back(cv::Point(bright_point.at(row).x + (col- bright_point.at(row).x)/2, row));break;}//if (rightmost.size() > 1) beginCol = rightmost.at(0).x - 30;}}

25、 拟合轮廓椭圆,去掉过宽的轮廓并画出剩余轮廓中最大那个

 cv::Mat  tmpMat = cv::Mat(thresholdMat.rows, thresholdMat.cols, CV_8UC1, cv::Scalar(0, 0, 0));cv::Mat  cimage = cv::Mat::zeros(tmpMat.size(), CV_8UC3);//可视化拟合椭圆结果//画出轮廓;int  count = 0;//for (k = contours.begin(); k != contours.end(); ++k, count++) //删除小连通域的//{// std::vector<cv::Point> curContours = *k;//   if (curContours.size() < 70) continue;// cv::drawContours(tmpMat, contours, count, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充//}//只画出最大的那个轮廓int maxContou_size = 0;int maxContou_index;vector<cv::Rect> boundRect;for (int i = 0; i < contours.size(); i++){std::vector<cv::Point> curContours = contours.at(i);if (curContours.size() < 40) continue;boundRect.push_back(cv::boundingRect(curContours));if (boundRect.at(boundRect.size() - 1).height < imgOriginal.rows / 6) continue;//轮廓的长度比图像的1/5短则直接过掉//---------------------------------------------------------------------------------------------- 拟合椭圆 开始(拟合椭圆的点至少为6)cv::Moments mu = cv::moments(curContours, false); //计算轮廓矩cv::Point2f mc = cv::Point2f(mu.m10 / mu.m00, mu.m01 / mu.m00); //轮廓质心// 拟合椭圆的长、短轴 大小;旋转角度、直径、离心率、圆滑度double area = mu.m00;                                  // 轮廓面积double perimeter = cv::arcLength(curContours, true);   // 轮廓周长cv::RotatedRect r = cv::fitEllipse(curContours);如果长宽比大于30,则排除,不做拟合//if (cv::MAX(r.size.width, r.size.height) > cv::MIN(r.size.width, r.size.height) * 30)//   continue;double majorAxis = r.size.height > r.size.width ? r.size.height : r.size.width; //长轴double minorAxis = r.size.height > r.size.width ? r.size.width : r.size.height; //短轴double orientation = r.angle - 90;                                  // 角度制double orientation_rads = orientation*CV_PI / 180;                  // 转化为弧度制double diameter = sqrt((4 * area) / 3.1416);                        // 直径double eccentricity = sqrt(1 - pow(minorAxis / majorAxis, 2));      // 离心率double roundness = pow(perimeter, 2) / (2 * 3.1416*area);           // 圆滑度//cv::arrowedLine(OutermostLayerMat, cv::Point(contourCenterPoint.x, contourCenterPoint.y), cv::Point(contourCenterPoint.x + 100 * cos(orientation_rads), contourCenterPoint.y + 100 * sin(orientation_rads)), cv::Scalar(0, 255, 0), 3, cv::LINE_8, 0, 0.5);//画箭头if (debug) printf("第%d个椭圆  偏移角度 = %.2f ,直径 = %.2f,离心率 = %.2f, 圆滑度 = %.2f  长轴=%.2f  短轴=%.2f  \n", i, orientation, diameter, eccentricity, roundness, majorAxis, minorAxis);ellipse(cimage, r, cv::Scalar(0, 0, 255), 1, CV_AA);//画出拟合的椭圆cv::drawContours(cimage, contours, i, cv::Scalar(195, 190, 0), -1, CV_AA, hierarchy); //填充if (debug) cv::imshow("拟合椭圆", cimage);//---------------------------------------------------------------------------------------------- 拟合椭圆 结束if (minorAxis >= 40) continue;//比较宽的椭圆轮廓的不画if (maxContou_size < curContours.size())//找出最大的那个轮廓并记录其下标{maxContou_size = curContours.size();maxContou_index = i;}//cv::drawContours(tmpMat, contours, i, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充}cv::drawContours(tmpMat, contours, maxContou_index, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //只画出最大的那个轮廓if (debug) cv::imshow("删除最小连通域tmpMat", tmpMat);//一个不为0的像素都没有,即全黑时,直接返回falseint iVal255 = cv::countNonZero(tmpMat);if (!iVal255) return 0;

26、删除最小连通域(丽姐发我的)

声明:

void RemoveSmallRegion(cv::Mat &Src, cv::Mat &Dst, int AreaLimit, int CheckMode, int NeihborMode);

定义:

void ImageProcessing::RemoveSmallRegion(cv::Mat & Src, cv::Mat & Dst, int AreaLimit, int CheckMode, int NeihborMode)
{int RemoveCount = 0;//新建一幅标签图像初始化为0像素点,为了记录每个像素点检验状态的标签,0代表未检查,1代表正在检查,2代表检查不合格(需要反转颜色),3代表检查合格或不需检查 //初始化的图像全部为0,未检查cv::Mat PointLabel = cv::Mat::zeros(Src.size(), CV_8UC1);if (CheckMode == 1)//去除小连通区域的白色点{cout << "去除小连通域.";for (int i = 0; i < Src.rows; i++){for (int j = 0; j < Src.cols; j++){if (Src.at<uchar>(i, j) < 10){PointLabel.at<uchar>(i, j) = 3;//将背景黑色点标记为合格,像素为3}}}}else//去除孔洞,黑色点像素{cout << "去除孔洞";for (int i = 0; i < Src.rows; i++){for (int j = 0; j < Src.cols; j++){if (Src.at<uchar>(i, j) > 10){PointLabel.at<uchar>(i, j) = 3;//如果原图是白色区域,标记为合格,像素为3}}}}vector<cv::Point2i>NeihborPos;//将邻域压进容器NeihborPos.push_back(cv::Point2i(-1, 0));NeihborPos.push_back(cv::Point2i(1, 0));NeihborPos.push_back(cv::Point2i(0, -1));NeihborPos.push_back(cv::Point2i(0, 1));if (NeihborMode == 1){cout << "Neighbor mode: 8邻域." << endl;NeihborPos.push_back(cv::Point2i(-1, -1));NeihborPos.push_back(cv::Point2i(-1, 1));NeihborPos.push_back(cv::Point2i(1, -1));NeihborPos.push_back(cv::Point2i(1, 1));}else cout << "Neighbor mode: 4邻域." << endl;int NeihborCount = 4 + 4 * NeihborMode;int CurrX = 0, CurrY = 0;//开始检测for (int i = 0; i < Src.rows; i++){for (int j = 0; j < Src.cols; j++){if (PointLabel.at<uchar>(i, j) == 0)//标签图像像素点为0,表示还未检查的不合格点{ //开始检查vector<cv::Point2i>GrowBuffer;//记录检查像素点的个数GrowBuffer.push_back(cv::Point2i(j, i));PointLabel.at<uchar>(i, j) = 1;//标记为正在检查int CheckResult = 0;for (int z = 0; z < GrowBuffer.size(); z++){for (int q = 0; q < NeihborCount; q++){CurrX = GrowBuffer.at(z).x + NeihborPos.at(q).x;CurrY = GrowBuffer.at(z).y + NeihborPos.at(q).y;if (CurrX >= 0 && CurrX<Src.cols&&CurrY >= 0 && CurrY<Src.rows) //防止越界 {if (PointLabel.at<uchar>(CurrY, CurrX) == 0){GrowBuffer.push_back(cv::Point2i(CurrX, CurrY)); //邻域点加入buffer PointLabel.at<uchar>(CurrY, CurrX) = 1;   //更新邻域点的检查标签,避免重复检查 }}}}if (GrowBuffer.size()>AreaLimit) //判断结果(是否超出限定的大小),1为未超出,2为超出 CheckResult = 2;else{CheckResult = 1;RemoveCount++;//记录有多少区域被去除}for (int z = 0; z < GrowBuffer.size(); z++){CurrX = GrowBuffer.at(z).x;CurrY = GrowBuffer.at(z).y;PointLabel.at<uchar>(CurrY, CurrX) += CheckResult;//标记不合格的像素点,像素值为2}//********结束该点处的检查********** }}}CheckMode = 255 * (1 - CheckMode);//开始反转面积过小的区域 for (int i = 0; i < Src.rows; ++i){for (int j = 0; j < Src.cols; ++j){if (PointLabel.at<uchar>(i, j) == 2){Dst.at<uchar>(i, j) = CheckMode;}else if (PointLabel.at<uchar>(i, j) == 3){Dst.at<uchar>(i, j) = Src.at<uchar>(i, j);}}}cout << RemoveCount << " objects removed." << endl;
}

调用:

 RemoveSmallRegion(thresholdMat, thresholdMat, 100, 1, 1);cv::imshow("RemoveSmallRegion", thresholdMat);

27、获取直激光的ROI区域减少运算量

函数声明:

 /*//获取直激光的ROI区域减少运算量(获取 大 的ROI)cv::Mat imgOriginal:原图cv::Point tlPoint:ROI的左上端点cv::Point brPoint:ROI的右下端点bool debug:是否开启调试信息*/bool getROI_CircleOrRectangle(cv::Mat imgOriginal, cv::Point &tlPoint, cv::Point &brPoint, bool debug = false);

函数定义:

bool ImageProcessing::getROI_CircleOrRectangle(cv::Mat imgOriginal, cv::Point & tlPoint, cv::Point & brPoint, bool debug)
{//if (tlPoint.x >= brPoint.x || tlPoint.y >= brPoint.y)//{//   printf("roi设置不合理!\n");//   return false;//}//if (abs(tlPoint.x - brPoint.x) > imgOriginal.cols || abs(tlPoint.y - brPoint.y) > imgOriginal.rows)//{//    printf("roi设置不合理!\n");//   return false;//}int time_start = clock();int time_end = clock();bool result = false;cv::Mat canvas;//可视化的画布imgOriginal.copyTo(canvas);tlPoint = cv::Point(0, 0);brPoint = cv::Point(imgOriginal.cols, imgOriginal.rows);//cv::Mat imgGray;//cv::Mat thresholdMat;//if (imgOriginal.type() != CV_8UC1)//   cv::cvtColor(imgOriginal, imgGray, cv::COLOR_BGR2GRAY);//else imgOriginal.copyTo(imgGray);//闭运算cv::Mat close;cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));cv::morphologyEx(imgOriginal, close, cv::MORPH_CLOSE, kernel);//闭操作cv::Mat imgGray;cv::Mat thresholdMat;if (close.type() != CV_8UC1)cv::cvtColor(close, imgGray, cv::COLOR_BGR2GRAY);else close.copyTo(imgGray);cv::adaptiveThreshold(imgGray, thresholdMat, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 51, -20);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); //查找外轮廓,压缩存储轮廓点if (contours.size() <= 0)//图为全黑时{cout << "contours.size() <= 0";return false;}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() < 70) continue;cv::drawContours(tmpMat, contours, count, cv::Scalar(255, 255, 255), -1, CV_AA, hierarchy); //用全黑色填充}if (debug) cv::imshow("删除最小连通域tmpMat", tmpMat);//一个不为0的像素都没有,即全黑时,直接返回falseint iVal255 = cv::countNonZero(tmpMat);if (!iVal255) return 0;//提取骨干点集std::vector<cv::Point> bright_point;//max点std::vector<int> bright_value;//max像素值bright_point = extrectBackbone(tmpMat, bright_value, debug);if (debug){printf("骨干点集更新前:\n");for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);printf("第%d 行, 【%d, %d】 灰度值:%d \n", i, curPoint.x, curPoint.y, curGray);}}//可视化骨干点集cv::Mat newArcMat = cv::Mat::zeros(tmpMat.size(), CV_8UC1);  //绘制 调试for (int i = 0; i < bright_point.size(); i++) //调试{cv::Point P = cv::Point(bright_point.at(i).x, bright_point.at(i).y);newArcMat.at<uchar>(cv::Point(bright_point.at(i).x, bright_point.at(i).y)) = 255;}cv::Mat  BowCurveMat;cv::Mat imgRGB;if (newArcMat.type() != CV_8UC1)cvtColor(newArcMat, imgRGB, cv::COLOR_RGB2GRAY);else newArcMat.copyTo(imgRGB);cv::addWeighted(tmpMat, 0.3, imgRGB, 0.7, 0, BowCurveMat); //重叠看效果//if (debug) cv::imshow("重叠看效果(初始)", BowCurveMat); //显示重叠效果int findDis = 50;vector<int> topList;vector<int> bottomList;for (int i = 0; i <= findDis; i++){topList.push_back(bright_point.at(i).x);}for (int i = bright_point.size() - 1; i >= bright_point.size() - 1 - findDis; i--){bottomList.push_back(bright_point.at(i).x);}//可视化for (int i = 0; i < topList.size(); i++){if (debug) printf("topList.at(%d)= %d       \n", i, topList.at(i));}if (debug) printf("------------------------\n");for (int i = 0; i < bottomList.size(); i++){if (debug) printf("bottomList.at(%d)= %d    \n", i, bottomList.at(i));}int  countMax_top, MaxCountY_top;//众数,众数的数量majorityElement(topList, MaxCountY_top, countMax_top);//参数1:传入的 需要求众数的 vectorif (debug) printf("得到的topList(众数) MaxCountY_top= %d     (众数的数量)countMax_top=%d  \n\n", MaxCountY_top, countMax_top);int  countMax_bottom, MaxCountY_bottom;//众数,众数的数量majorityElement(bottomList, MaxCountY_bottom, countMax_bottom);//参数1:传入的 需要求众数的 vectorif (debug) printf("得到的bottomList(众数) MaxCountY_bottom= %d     (众数的数量)countMax_bottom=%d  \n\n", MaxCountY_bottom, countMax_bottom);tlPoint.x = MaxCountY_top - 50;brPoint.x = MaxCountY_bottom + 100;cv::Rect rect = cv::Rect(tlPoint.x, tlPoint.y, brPoint.x - tlPoint.x, brPoint.y - tlPoint.y);cv::rectangle(canvas, rect, cv::Scalar(0, 0, 255), 1, 8, 0);printf("getROI_CircleOrRectangle函数中--------得出ROI:tl【%d, %d】- br【%d, %d】 \n", tlPoint.x, tlPoint.y, brPoint.x, brPoint.y);result = true;//canvas.copyTo(lap_o.canvas);if (debug){//cv::namedWindow("重叠看效果", cv::WINDOW_FREERATIO); //可调整显示图片的窗口大小if (debug) cv::imshow("重叠看效果", BowCurveMat); //显示重叠效果cv::imshow("imgGray", imgGray);cv::imshow("thresholdMat", thresholdMat);cv::imshow("删除最小连通域tmpMat", tmpMat);cv::imshow("闭运算", close); //闭运算//cv::namedWindow("canvas可视化效果", cv::WINDOW_FREERATIO); //可调整显示图片的窗口大小cv::imshow("canvas可视化效果", canvas);}time_end = clock();printf("\n耗时 %d ms \n", time_end - time_start);return result;
}

函数调用示例:

     bool res = false;cv::Point tlPoint_big;cv::Point brPoint_big;res = pd.getROI_CircleOrRectangle(imgOriginal, tlPoint_big, brPoint_big, true);if (res){cout << "返回结果是 true !" << endl;printf("主函数出来后----------得出ROI:tl【%d, %d】- br【%d, %d】 \n", tlPoint_big.x, tlPoint_big.y, brPoint_big.x, brPoint_big.y);cv::Rect rect = cv::Rect(tlPoint_big.x, tlPoint_big.y, brPoint_big.x - tlPoint_big.x, brPoint_big.y - tlPoint_big.y);cv::rectangle(canvas, rect, cv::Scalar(0, 0, 255), 1, 8, 0);}else{cout << "返回结果是 false !" << endl;cv::line(canvas, cv::Point(60, 60), cv::Point(1000, 1000), cv::Scalar(0, 0, 200), 1, cv::LINE_AA, 0);}res = false;res = pd.RoundHole_Detection_diameterROI(imgOriginal, top, bottom, tlPoint_big.y, brPoint_big.y, tlPoint_big.x, brPoint_big.x, canvas, true);//res = pd.RoundHole_Detection_diameter(imgOriginal, top, bottom, canvas, true);if (res){cout << "返回结果是 true !" << endl;printf("主函数出来后----------得出:top【%d, %d】- bottom【%d, %d】 \n", top.x, top.y, bottom.x, bottom.y);}else{cout << "返回结果是 false !" << endl;cv::line(canvas, cv::Point(60, 60), cv::Point(1000, 1000), cv::Scalar(0, 0, 200), 1, cv::LINE_AA, 0);}

28、 删除 vector 的开头和末尾部分的 cv::Point(0, 0)无效点

 //-------------------------------------------------------------- 删除无效点 开始(删除开头和末尾部分的 cv::Point(0, 0))if (debug){printf("骨干点集更新前:\n");for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);int curGray = bright_value.at(i);if (debug) printf("骨干点集更新前:  第%d 行, 【%d, %d】 灰度值:%d  \n", i, curPoint.x, curPoint.y, curGray);}}//删除开头的无效点std::vector<cv::Point> tempPoint;bool beginFlag = false;for (int i = 0; i < bright_point.size(); i++){cv::Point curPoint = bright_point.at(i);if (curPoint != cv::Point(0, 0)) beginFlag = true;if (beginFlag) tempPoint.push_back(curPoint);}bright_point = tempPoint;//删除结尾的无效点for (int i = bright_point.size() - 1; i >= 0; i--){cv::Point curPoint = bright_point.at(i);if (curPoint != cv::Point(0, 0)) break;else{bright_point.pop_back();//删除 vector 中的最后一个元素}}//-------------------------------------------------------------- 删除无效点 结束

29、 计算两点间距离

函数声明:

 //计算两点间距离double distanced(cv::Point p1, cv::Point p2);

函数定义:

//计算两点间距离
double ImageProcessing::distanced(cv::Point p1, cv::Point p2)
{return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
}

函数调用示例:

     double width;width = distanced(top, bottom);

30、裁剪图像

函数声明:

 /*//裁剪图片cv::Mat imgOriginal:原图cv::Point tlPoint:ROI的左上端点cv::Point brPoint:ROI的右下端点bool debug:是否开启调试信息*/bool Croping(cv::Mat &imgOriginal, cv::Point tlPoint, cv::Point brPoint, bool debug = false);

函数定义:

bool ImageProcessing::Croping(cv::Mat &imgOriginal, cv::Point tlPoint, cv::Point brPoint, bool debug)
{if (tlPoint.x >= brPoint.x || tlPoint.y >= brPoint.y){cv::Mat m = cv::Mat::zeros(imgOriginal.size(), CV_8UC1);m.copyTo(imgOriginal);printf("Croping  roi设置不合理!  tlPoint.x%d >= brPoint.x%d || tlPoint.y%d >= brPoint.y%d\n", tlPoint.x , brPoint.x, tlPoint.y, brPoint.y);return false;}if (abs(tlPoint.x - brPoint.x) > imgOriginal.cols || abs(tlPoint.y - brPoint.y) > imgOriginal.rows){cv::Mat m = cv::Mat::zeros(imgOriginal.size(), CV_8UC1);m.copyTo(imgOriginal);printf("Croping  roi设置不合理!   abs(tlPoint.x - brPoint.x)%d > imgOriginal.cols%d || abs(tlPoint.y - brPoint.y)%d > imgOriginal.rows%d\n", abs(tlPoint.x - brPoint.x), imgOriginal.cols, abs(tlPoint.y - brPoint.y), imgOriginal.rows);return false;}cv::Rect rect = cv::Rect(tlPoint.x, tlPoint.y, brPoint.x - tlPoint.x, brPoint.y - tlPoint.y);if (debug){cv::Mat canvas;imgOriginal.copyTo(canvas);cv::rectangle(canvas, rect, cv::Scalar(0, 0, 255), 1, 8, 0);cv::imshow("裁剪效果示意图", canvas);}imgOriginal = imgOriginal(rect);if (debug) cv::imshow("裁剪效果", imgOriginal);return true;
}

函数调用示例:

 bool result;//printf("Croping    imgOriginal.cols%d  imgOriginal.rows%d\n", src.cols, src.rows);result = Croping(src, cv::Point(ROI_left, ROI_top), cv::Point(ROI_right, ROI_bottom), debug);if (result == false) return result;//若ROI不合理,直接返回falseif (debug) cv::imshow("裁剪效果", src);

31、获取最大内切圆(内切圆)

函数声明:

 void FindInnerCircleInContour(std::vector<cv::Point> contour, cv::Point2f &center, float &radius);//找内接圆

函数定义:

void ImageProcessing::FindInnerCircleInContour(std::vector<cv::Point> contour, cv::Point2f &center, float &radius)
{cv::Rect r = cv::boundingRect(contour);int nL = r.x, nR = r.br().x; //轮廓左右边界int nT = r.y, nB = r.br().y; //轮廓上下边界double dist = 0;double maxdist = 0;//cv::Mat  distMat = cv::Mat::zeros(m_ImgWidth, m_ImgHeight, CV_32F);  //定义一个Mat对象,存放原图中每个点到该轮廓的距离,为浮点型数据for (int i = nL; i<nR; i++)  //列{for (int j = nT; j<nB; j++)  //行{//计算轮廓内部各点到最近轮廓点的距离dist = cv::pointPolygonTest(contour, cv::Point2f(i, j), true);//printf("(%d,%d)  dist= %f  ***************************  \n" ,i, j, dist);if (dist>maxdist){//求最大距离,只有轮廓最中心的点才距离最大maxdist = dist;center = cv::Point2f(i, j);}//通过点多边形检测计算获得点到轮廓距离,并存放至dist中//distMat.at<float>(i, j) = cv::pointPolygonTest(contour, cv::Point(i, j), true);}}radius = maxdist;  //圆半径//计算dist中,最大值和最小值,以及其位置坐标//double minVal, maxVal;//cv::Point maxloc, minloc;//cv::minMaxLoc(distMat, &minVal, &maxVal, &minloc, &maxloc);//radius = fabs(maxVal);   //对最大值求绝对值,即为内接圆半径//center = maxloc;   //某点与轮廓距离为最大值,则该点为内接圆圆心
}

函数调用:

 //----------------------------------------------------------------------- 找内切圆圆心、半径std::vector<std::vector<cv::Point>>  contours2;std::vector<cv::Vec4i> hierarchy;cv::Mat imageContours = cv::Mat::zeros(image.size(), image.type());cv::Mat Contours = cv::Mat::zeros(image.size(), image.type());  //绘制cv::findContours(image, contours2, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_TC89_L1, cv::Point(0, 0));if (contours2.size() == 0){return 0;}cv::Point2f center;float radius;vector<cv::Point2f> centerList;vector<float> radiusList;float maxRadius = 0;//最大半径int maxRadiusIndex = 0;for (int i = 0; i < contours2.size(); i++){FindInnerCircleInContour(contours2.at(i), center, radius); //轮廓最大内切圆centerList.push_back(center);radiusList.push_back(radius);if (debug) printf("contours2.at(%d) 内切圆的圆心center:【%f, %f】  radius = %f  \n", i, center.x, center.y, radius);//if (maxRadius < radius){maxRadius = radius;maxRadiusIndex = i;}}if (debug) printf("最大内切圆contours2.at(%d),center【%f, %f】,radius = %f  \n", maxRadiusIndex,centerList.at(maxRadiusIndex).x, centerList.at(maxRadiusIndex).y, radiusList.at(maxRadiusIndex));spot_Diameter = maxRadius;//----------------------------------------------------------------------- 找内切圆圆心、半径  结束

32、获取空间上两点间距离

 cv::Point3d diff = cv::Point3d(X1, Y1, Z1) - cv::Point3d(X2, Y2, Z2);dis = cv::norm(diff);

norm就是模长,计算两个2D点间距离亦可,写法同3D。

33、

工业视觉需要时可抄的代码---持续更新相关推荐

  1. C语言图形函数代码~持续更新中

    下面总结的是一些C语言图形函数代码~持续更新中 画三类圆 #include#include#include#include#includeint main(void) { initgraph(640, ...

  2. Android开发人员不得不收集的代码(持续更新中)(http://www.jianshu.com/p/72494773aace,原链接)

    Android开发人员不得不收集的代码(持续更新中) Blankj 关注 2016.07.31 04:22* 字数 370 阅读 102644评论 479喜欢 3033赞赏 14 utilcode D ...

  3. Matlab常用代码---持续更新

    Matlab中的一些常用代码---持续更新 1. 获取当前的工作目录路径:添加文件夹到工作路径 2. 获取某个.m文件的绝对路径 3. 使用随机颜色进行可视化 1. 获取当前的工作目录路径:添加文件夹 ...

  4. 做事时杂乱的记录 【持续更新】【因有借鉴,就归为转载吧】

    [博客只是做个记录,技术性不强,能给游客提供帮助,最好不过.错误或模棱两可的地方,还望不吝斧正.--写在前面] 1. 大家工作的时候都写过周报.月报吧. 自己比较习惯做笔录,回首时能知道自己干了些什么 ...

  5. 阿里开发10年大牛:Android开发人员不得不收集的代码(持续更新中)

    前言 1.软件吃掉世界,而机器学习正吃掉软件 在数据爆炸的时代,如何创建「智能系统」成为焦点.这些应用程序内所体现的智能技术,并非是将实用指令添加到代码中,而是可以让软件自己去识别真实世界中发生的事件 ...

  6. java程序员一天多少行有效代码,持续更新~

    Java程序员应该知道的20个有用的库经验丰富的优秀Java开发人员的一个特点是对API(包括JDK和第三方库)有广泛的了解.今天分享一些Java开发人员应该熟悉的最有用.最基本 程序员经常会因为不编 ...

  7. VS2019-写opengl时Bugs合集(持续更新)

    ERROR::SHADER::PROGRAM::LINKING_FAILED Attached vertex shader is not compiled. 相对路径返回上一级用"../.. ...

  8. 【Keil】使用Keil5时出现的错误(持续更新)

    目录 1.常见编译错误 2.常见逻辑错误 3.常见仿真错误 1.常见编译错误 error C141: `syntax error near 'extern', expected 'hdata'` (错 ...

  9. 知道创宇爬虫题--代码持续更新中

    网上流传着知道创宇的一道爬虫题,虽然一直写着一些实用的爬虫,但真正写出这个一个规范要求的"工具",还是学到了不少东西.先看下题目: 使用python编写一个网站爬虫程序,支持参数如 ...

最新文章

  1. java打包没有src_maven 打包时,src/main/java目录下的xml等资源文件没有打包进去的问题...
  2. 全球首富贝佐斯离婚协议达成,前妻获383亿美元
  3. 远程连接CentOS的MySQL报错:Can't connect to MySQL server on 'XXX' (13)
  4. 你不得不学Python的7个理由!
  5. openssl工具调试ssl加密ftp
  6. javascript --- js中的事件
  7. 分段线性拟合经典案例:计算多年气温最低值和最高值的分段线性变化趋势(附分段线性拟合工具下载)
  8. 学法减分小程序可用可运营源码附带安装教程
  9. 各地延迟上课,请收好这份线上教学操作指南
  10. 题目1022:游船出租(结构体使用)
  11. map转json,json转对象
  12. UG NX 12.0入门
  13. Applet 小应用程序查看器 乱码(小方块)
  14. arcengine 加载地图不显示_Devexpress使用后arcengine地图加载不能全图显示
  15. Halcon 算子 elliptic_axis
  16. signature=e7a4f21fa0bd38abc7e1a2451a8b7b26,Win10 14328起“迅雷7.9、迅雷极速版”崩溃修正补丁...
  17. ERP与CRM、MRP、PLM、APS、MES、WMS、SRM的关系
  18. Python3.6下CMD命令安装ipython
  19. 使用CLB部署HTTPS业务
  20. Javascript 实现gb2312和utf8编码的互换

热门文章

  1. Qt利用openGL绘制三棱锥
  2. python画圣诞树
  3. FL Studio20.8完整版注册密钥下载有哪些新功能?
  4. 模拟器左下方数字含义
  5. 敢用这张图片做“壁纸”手机秒变砖!
  6. html5设置app启动页,使用Ken Burns Effect制作App启动页
  7. ARM Cortex-M 系列 MCU 芯片选型
  8. 安全生产预警系统软件解决方案
  9. 汉字数组,配合转换拼音
  10. LED、LCD背光源、CCFL