#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <stdio.h>
using namespace std;
using namespace cv;//-----------------------------------【全局变量声明部分】--------------------------------------
//      描述:全局变量声明
//-----------------------------------------------------------------------------------------------
Mat g_srcImage, g_dstImage, g_midImage, g_grayImage, imgHSVMask;//原始图、中间图和效果图
int threshold_value = 60;  //阈值
int size = 800;                //面积因子
float start_time,end_time,sum_time; //处理时间//-----------------------------------【全局函数声明部分】--------------------------------------
//      描述:全局函数声明
//-----------------------------------------------------------------------------------------------
void ThinSubiteration1(Mat & pSrc, Mat & pDst);
void ThinSubiteration2(Mat & pSrc, Mat & pDst);
void normalizeLetter(Mat & inputarray, Mat & outputarray);
void Line_reflect(Mat & inputarray, Mat & outputarray);
void Delete_smallregions(Mat & pSrc, Mat & pDst);//-----------------------------------【main( )函数】--------------------------------------------
//      描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main( )
{ //载入原始图g_srcImage = imread("3.jpg");  //读取素材图start_time = getTickCount(); //开始处理时间//显示灰度图  cvtColor(g_srcImage, g_grayImage, CV_RGB2GRAY);imshow("【灰度图】", g_grayImage); //二值化threshold(g_grayImage, imgHSVMask, threshold_value, 255, THRESH_BINARY);g_midImage = Mat::zeros(imgHSVMask.size(), CV_8UC1);  //绘制//去除小面积区域Delete_smallregions(imgHSVMask, g_midImage);imshow("【目标图】", g_midImage);imwrite("Target_image3.jpg", g_midImage);//normalizeLetter显示效果图  normalizeLetter(g_midImage,g_dstImage);imshow("【效果图】", g_dstImage);  //曲线映射到原图
/*  threshold(g_grayImage, g_midImage, threshold_value, 255, CV_THRESH_BINARY); */
/*  imshow("【二值化图】", g_midImage);                                         */Line_reflect(g_dstImage,g_midImage);imshow("【映射图】", g_midImage); imwrite("Reflect_image3.jpg", g_midImage);//转换类型,保存skeleton图像normalize(g_dstImage, g_midImage, 0, 255, NORM_MINMAX, CV_8U);   imwrite("Thinning_image3.jpg", g_midImage);//计算运行时间end_time = getTickCount();sum_time = (end_time - start_time)/ getTickFrequency();printf("%lf s",sum_time);waitKey(0);  return 0;  }void ThinSubiteration1(Mat & pSrc, Mat & pDst) {int rows = pSrc.rows;int cols = pSrc.cols;pSrc.copyTo(pDst);for(int i = 0; i < rows; i++) {for(int j = 0; j < cols; j++) {if(pSrc.at<float>(i, j) == 1.0f) {/// get 8 neighbors/// calculate C(p)int neighbor0 = (int) pSrc.at<float>( i-1, j-1);int neighbor1 = (int) pSrc.at<float>( i-1, j);int neighbor2 = (int) pSrc.at<float>( i-1, j+1);int neighbor3 = (int) pSrc.at<float>( i, j+1);int neighbor4 = (int) pSrc.at<float>( i+1, j+1);int neighbor5 = (int) pSrc.at<float>( i+1, j);int neighbor6 = (int) pSrc.at<float>( i+1, j-1);int neighbor7 = (int) pSrc.at<float>( i, j-1);int C = int(~neighbor1 & ( neighbor2 | neighbor3)) +int(~neighbor3 & ( neighbor4 | neighbor5)) +int(~neighbor5 & ( neighbor6 | neighbor7)) +int(~neighbor7 & ( neighbor0 | neighbor1));if(C == 1) {/// calculate Nint N1 = int(neighbor0 | neighbor1) +int(neighbor2 | neighbor3) +int(neighbor4 | neighbor5) +int(neighbor6 | neighbor7);int N2 = int(neighbor1 | neighbor2) +int(neighbor3 | neighbor4) +int(neighbor5 | neighbor6) +int(neighbor7 | neighbor0);int N = min(N1,N2);if ((N == 2) || (N == 3)) {/// calculate criteria 3int c3 = ( neighbor1 | neighbor2 | ~neighbor4) & neighbor3;if(c3 == 0) {pDst.at<float>( i, j) = 0.0f;}}}}}}
}void ThinSubiteration2(Mat & pSrc, Mat & pDst) {int rows = pSrc.rows;int cols = pSrc.cols;pSrc.copyTo( pDst);for(int i = 0; i < rows; i++) {for(int j = 0; j < cols; j++) {if (pSrc.at<float>( i, j) == 1.0f) {/// get 8 neighbors/// calculate C(p)int neighbor0 = (int) pSrc.at<float>( i-1, j-1);int neighbor1 = (int) pSrc.at<float>( i-1, j);int neighbor2 = (int) pSrc.at<float>( i-1, j+1);int neighbor3 = (int) pSrc.at<float>( i, j+1);int neighbor4 = (int) pSrc.at<float>( i+1, j+1);int neighbor5 = (int) pSrc.at<float>( i+1, j);int neighbor6 = (int) pSrc.at<float>( i+1, j-1);int neighbor7 = (int) pSrc.at<float>( i, j-1);int C = int(~neighbor1 & ( neighbor2 | neighbor3)) +int(~neighbor3 & ( neighbor4 | neighbor5)) +int(~neighbor5 & ( neighbor6 | neighbor7)) +int(~neighbor7 & ( neighbor0 | neighbor1));if(C == 1) {/// calculate Nint N1 = int(neighbor0 | neighbor1) +int(neighbor2 | neighbor3) +int(neighbor4 | neighbor5) +int(neighbor6 | neighbor7);int N2 = int(neighbor1 | neighbor2) +int(neighbor3 | neighbor4) +int(neighbor5 | neighbor6) +int(neighbor7 | neighbor0);int N = min(N1,N2);if((N == 2) || (N == 3)) {int E = (neighbor5 | neighbor6 | ~neighbor0) & neighbor7;if(E == 0) {pDst.at<float>(i, j) = 0.0f;}}}}}}
}void normalizeLetter(Mat & inputarray, Mat & outputarray) {bool bDone = false;int rows = inputarray.rows;int cols = inputarray.cols;inputarray.convertTo(inputarray,CV_32FC1);inputarray.copyTo(outputarray);outputarray.convertTo(outputarray,CV_32FC1);/// pad sourceMat p_enlarged_src = Mat(rows + 2, cols + 2, CV_32FC1);for(int i = 0; i < (rows+2); i++) {p_enlarged_src.at<float>(i, 0) = 0.0f;p_enlarged_src.at<float>( i, cols+1) = 0.0f;}for(int j = 0; j < (cols+2); j++) {p_enlarged_src.at<float>(0, j) = 0.0f;p_enlarged_src.at<float>(rows+1, j) = 0.0f;}for(int i = 0; i < rows; i++) {for(int j = 0; j < cols; j++) {if (inputarray.at<float>(i, j) >= threshold_value) {            //调参p_enlarged_src.at<float>( i+1, j+1) = 1.0f;}elsep_enlarged_src.at<float>( i+1, j+1) = 0.0f;}}/// start to thinMat p_thinMat1 = Mat::zeros(rows + 2, cols + 2, CV_32FC1);Mat p_thinMat2 = Mat::zeros(rows + 2, cols + 2, CV_32FC1);Mat p_cmp = Mat::zeros(rows + 2, cols + 2, CV_8UC1);while (bDone != true) {/// sub-iteration 1ThinSubiteration1(p_enlarged_src, p_thinMat1);/// sub-iteration 2ThinSubiteration2(p_thinMat1, p_thinMat2);/// comparecompare(p_enlarged_src, p_thinMat2, p_cmp, CV_CMP_EQ);    //比较输入的src1和src2中的元素,真为255,否则为0/// checkint num_non_zero = countNonZero(p_cmp);                  //返回灰度值不为0的像素数if(num_non_zero == (rows + 2) * (cols + 2)) {bDone = true;}/// copyp_thinMat2.copyTo(p_enlarged_src);}// copy resultfor(int i = 0; i < rows; i++) {for(int j = 0; j < cols; j++) {outputarray.at<float>( i, j) = p_enlarged_src.at<float>( i+1, j+1);}}
}void Line_reflect(Mat & inputarray, Mat & outputarray)
{int rows = inputarray.rows;int cols = inputarray.cols;for(int i = 0; i < rows; i++) {for(int j = 0; j < cols; j++) {if (inputarray.at<float>(i, j) == 1.0f) {outputarray.at<float>( i, j) = 0.0f;}}}
}// 提取连通区域,并剔除小面积联通区域
void Delete_smallregions(Mat & pSrc, Mat & pDst)
{vector<vector<Point>> contours;           //二值图像轮廓的容器vector<Vec4i> hierarchy;                  //4个int向量,分别表示后、前、父、子的索引编号findContours(pSrc, contours, hierarchy,RETR_LIST, CHAIN_APPROX_NONE);             //检测所有轮廓vector<vector<Point>>::iterator k;                    //迭代器,访问容器数据for (k = contours.begin(); k != contours.end();)      //遍历容器,设置面积因子{if (contourArea(*k, false) < size){//删除指定元素,返回指向删除元素下一个元素位置的迭代器k = contours.erase(k);}else++k;}//contours[i]代表第i个轮廓,contours[i].size()代表第i个轮廓上所有的像素点for (int i = 0; i < contours.size(); i++){for (int j = 0; j < contours[i].size(); j++){//获取轮廓上点的坐标Point P = Point(contours[i][j].x, contours[i][j].y);}drawContours(pDst, contours,i, Scalar(255), -1, 8);}
}

具体例子

原图:

提取所需要线段图:

骨骼化:

将骨骼化的曲线段映射到原图:

【OpenCV图像处理】激光条纹线段提取、中心线提取相关推荐

  1. 【必备知识】:线激光条纹中心线提取算法导读

    线激光条纹特性 线激光器是由点激光器和前置透镜组成的.点激光器可以为He-Ne激光器或半导体激光器.相比较He-Ne激光器,半导体激光器因其输出光源具有发散性,更适合用于制作线激光器.需要说明的是,半 ...

  2. 基于灰度质心法和骨架的激光中心线提取

    之前博主一直在做线结构光成像,硬件比较垃圾,相机加镜头和线激光器总共成本在1000以内,精度在0.1mm左右,感觉这种成本做出来还是不错的,其实主要大部分时间花在了分析上来达到最好的效果. 一般对于激 ...

  3. 传统激光条纹中心提取算法研究现状

    传统激光条纹中心提取算法研究现状 前言 一.边缘法 二.中心法 三.阈值法 四. 细化法 五.极值法 六.灰度重心法 七.方向模板 八.曲线拟合法 九.Steger 前言 光条中心提取是将宽度大于1的 ...

  4. 激光条纹中心提取——方法总结

    激光条纹中心提取--方法总结 算法 优势 缺点 边缘法 处理速度快:适用于精度要求低的大型物体测量 存在很大误差:要求图像质量较好且结构光特性较高 中心法 适用于条纹质量好且形状规则的物体测量:精度高 ...

  5. 激光条纹中心提取——灰度中心法python

    激光条纹中心提取--灰度中心法python 灰度中心法 python代码 灰度中心法 灰度重心法是根据每行光条纹横截面内的灰度分布特征逐行进行处理,通过在行坐标的方向上,逐行计算提取光条纹区域的灰度重 ...

  6. Opencv图像处理——水平线和垂直线的提取

    Opencv图像处理--水平线和垂直线的提取 检测原理 图像形态学操作,可以通过自定义的结构元素实现结构元素对输入图像一些对象敏感.另外一些对象不敏感,这样就会让敏感的对象改变而不敏感的对象保留输出. ...

  7. Steger算法(Line_Gauss)-光条中心线提取(基于Hessian矩阵)

    Steger算法(Line_Gauss)-光条中心线提取(基于Hessian矩阵) 算法背景介绍 Hessian 矩阵与泰勒多项式 关于求t 导数与中心点.亚像素点 高斯函数作用 文献 算法背景介绍 ...

  8. 利用matlab提取中心线

    先看看代码运行结果(红色部分表示河流中心线,黑色表示河流两岸!): 注: 1. 由于河流两岸的坐标不是等距采样,所以无法保证100%准确,只要按着要求处理河岸坐标数据Shape文件,能保证95%以上能 ...

  9. 灰度重心法提取中心线遇到的问题

    import cv2 img = cv2.imread("E:/tuku/2019-10-28_10_36_21_370.bmp",0) median = cv2.Gaussian ...

  10. OPENCV之寻找并绘制轮廓以及提取轮廓重心坐标

    OPENCV之寻找并绘制轮廓以及提取轮廓重心坐标 1.寻找轮廓 声明:在寻找图像轮廓之前需要对图像进行阈值分割或者Canny.拉普拉斯等边缘检测算子处理. 寻找轮廓的算子: findContours( ...

最新文章

  1. Django博客系统(用户中心修改)
  2. 刚刚,Python 3.10 正式发布了!我发现了一个可怕的功能...
  3. oracle入门很简单豆瓣,Oracle入门经典
  4. 跟我一起做面试题-linux线程编程(2)
  5. Cocos2d-x三种定时器启用和停止
  6. linux 第三章目录文件管理(上)
  7. 排列组合计算问题中的卡塔兰数(Catalan Number)
  8. C语言十进制转换二进制
  9. matlab 编写雷达波形,雷达信号处理+Matlab程序
  10. HTML5 progress进度条详解
  11. tcpdump 文件权限相关问题
  12. 网页版第三方登录操作——微信登录
  13. Spark RDD 极简教程
  14. SQLServer将日期转换成字符串格式
  15. 使用servlet获得客户端与服务器的信息
  16. vue 给iframe设置src_vue项目中,iframe的src动态赋值
  17. 【计算机视觉学习一】计算机视觉简述
  18. 密码学之DES/AES算法
  19. 微小宝公众号排行榜_公众号榜单 | 2020·5月公众号地区排行榜重磅发布
  20. 【译】第三篇 SQL Server安全主体和安全对象

热门文章

  1. 十二、I/O复用介绍
  2. 第三季-第21课-多线程同步
  3. C++--第25课 - 异常处理 - 上
  4. 多线程编程中锁的种类与应用举例
  5. 单库单服解决方案terraform部署实践
  6. layui表单元素的radio单选框问题
  7. golang 最小堆排序实现
  8. 前端小白案例-爱新鲜抽屉式特效制作
  9. [译] TensorFlow 教程 #15 - 风格迁移
  10. MySQL 5.7: Page Cleaner的刷脏问题