在这之前,我们需要了解一下SLC文件的格式,只有对格式有一点了解,我们才能做接下来的工作,首先SLC文件中是通过描述各层中的多段线来描述整个模型的,多段线之间两两相连。对单个轮廓来说,最后一点必须等于第一点的坐标,同一组多段线头尾坐标是一样的,另外同一层可能会有多组多段线,为了描述方便,下面用“轮廓”一词来代替“多段线”。SLC文件携带的有用信息有模型XYZ方向的最大与最小坐标、层厚(单位:mm)、当前层高(单位:mm)、轮廓坐标(单位:mm),所以文件未携带的参数是要通过设备一侧来进行设置的。

SLC文件格式说明:https://chenjy1225.github.io/2018/03/16/slc-file-format/
       
     上图表示的是两组轮廓,一个顺时针,一个逆时针,通过顺逆时针的走向来确定填充的位置,从图中可以看出,填充的位置始终是轮廓走向的左侧。

下图是实际读取到的其他文件中的其中一组轮廓坐标,它的头尾坐标是一样的
                                             

代码

//OpenCV的轮廓查找和填充  https://blog.csdn.net/garfielder007/article/details/50866101
//opencv findContours和drawContours使用方法  https://blog.csdn.net/ecnu18918079120/article/details/78428002
//OpenCV关于容器的介绍  https://blog.csdn.net/Ahuuua/article/details/80593388//opencv
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>       //write read等函数
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/fs.h>
#include <stdio.h>
#include <iostream>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <pthread.h>      //包线程要包含
#define UNIX_DOMAIN "/tmp/UNIX.domain"
//using namespace cv;
using namespace std;char file_continue_flag = 0; //解析标志,为1则继续解析,覆盖原来的图片float z_level = 0;//字符数组中查找字符串或字符数组
//pSrc:原字符
//srcSize:原字符长度
//pDest:比对的字符
//dstSize:比对的字符的长度
int FindString(char pSrc[], int srcSize, char pDest[], int dstSize)
{int iFind = -1;for(size_t i=0;i<(size_t)srcSize;i++){int iCnt = 0;for (size_t j=0; j<(size_t)dstSize; j++) {if(pDest[j] == pSrc[i+j])iCnt++;}if (iCnt==dstSize) {iFind = i;break;}}return iFind;//返回比对的字符起始位置
}void OpenSLC(const char file_dir[])
{FILE *fd_temp;  //将数据保存到文本区//保存调试数据到文件夹fd_temp=fopen("./temp.txt", "w+");/************处理文件头的字符变量,解析完毕后,关闭当前文件*********************///关于文件的文件头变量char str_temp[300];float minx, maxx, miny, maxy, minz, maxz;FILE * fid = fopen(file_dir,"r");//用于处理文件头的信息if(fid == NULL){return;}//此处添加文件头处理方式fread(str_temp,sizeof(char),300,fid);//-EXTENTS <minx,maxx miny,maxy minz,maxz> CAD模型 x,y,z轴的范围int ssss = FindString(str_temp,300,(char *)"-EXTENTS",8);strncpy(str_temp,str_temp+ssss,100);//提取出XYZ的范围数据//提取XYZ的范围(前6个浮点值)char str[100];//无关变量sscanf(str_temp, "%[(A-Z)|^-]%f%[(^ )|(^,)]%f%[(^ )|(^,)]%f%[(^ )|(^,)]%f%[(^ )|(^,)]%f%[(^ )|(^,)]%f%[(A-Z)|^*]", str, &minx, str, &maxx, str, &miny, str, &maxy, str, &minz, str, &maxz, str);printf("%.3f %.3f %.3f %.3f %.3f %.3f\r\n", minx,maxx,miny,maxy, minz, maxz);// printf("%s\r\n", str_temp);fprintf(fd_temp,"%s\r\n",str_temp);fclose(fid);/*********************************************************************************/int fd;      //文件描述符char m_data; //读取到的数据float d = 0;    //d > 0 从上往下看是逆时针int size=0;       //读取到的数据长度fd = open(file_dir, O_RDONLY);///*// O_CREAT 若欲打开的文件不存在则自动建立该文件。// O_RDONLY 以只读方式打开文件// O_WRONLY 以只写方式打开文件*///【1】CV_8UC1---则可以创建----8位无符号的单通道---灰度图片------grayImg//【2】CV_8UC3---则可以创建----8位无符号的三通道---RGB彩色图像---colorImg //【3】CV_8UC4--则可以创建-----8位无符号的四通道---带透明色的RGB图像 Mat dst = Mat::zeros(1920, 1080, CV_8UC1);//生成的图片,其分辨率由实际的FrameBuffer来决定CvScalar color=cvScalar(0);vector<Point> contour;           //单个轮廓坐标值vector<vector<Point>> v_contour; //当前层所有轮廓集合vector<int> flag_swap_vector;   //轮廓排序用vector<vector<Point>> vctint;    //轮廓排序用float flag_swap=0;              //轮廓排序用unsigned int i=0;unsigned int j=0;unsigned int n_boundary,n_vertices,n_gaps;float   n_float,n_layer;float   n_polylineX,n_polylineY;/**************************处理头文件部分**************************/while(1){i++;if(i==2048){printf("file error\r\n");fprintf(fd_temp,"file error\r\n");close(fd);//关闭调试输出的数据文件fclose(fd_temp);//return;}size = read(fd, &m_data, 1);// printf("m_data=%x\r\n", m_data);switch(m_data){case 0x0d:j=1;break;case 0x0a:if(j==1)j=2;break;case 0x1a:if(j==2)j=3;break;default:j=0;break;}if(j==3)break;}printf("size=%d\r\n", size);/******************************************************************//***************************处理预留部分***************************/for(i=0;i<256;i++){size = read(fd, &m_data, 1);// fprintf(fd_temp,"m_data=%x\r\n",m_data);}/******************************************************************//**************************处理样本表部分**************************/size = read(fd, &m_data, 1);// printf("Sampling Table Size=%x\r\n", m_data);// fprintf(fd_temp,"Sampling Table Size=%x\r\n",m_data);while(m_data){size = read(fd, &n_float, 4);//Minimum Z Levelsize = read(fd, &n_float, 4);//Layer Thickness// printf("Layer Thickness=%.5f\r\n",n_float);fprintf(fd_temp,"Layer Thickness=%.5f\r\n",n_float);// m_parameter->n_HLayer=n_float;//n_totalLayers=(int)((zmax-zmin)/n_float);    //计算出来的总层数size = read(fd, &n_float, 4);    //Line Width Compensationsize = read(fd, &n_float, 4);    //Reservedm_data--;}int sss=0;// /******************************************************************/// /*************************处理轮廓数据部分*************************/while(1){sss++;size = read(fd, &n_layer, 4);fprintf(fd_temp,"Z轴高度=%.5f\r\n",n_layer);size = read(fd, &n_boundary, 4);fprintf(fd_temp,"轮廓数=%d\r\n",n_boundary);if(n_boundary==0xFFFFFFFF)  //结束符break;for(i=0;i<n_boundary;i++)   //把同一层多个轮廓都放在同一容器中,{                           //显示跟数据处理时 要根据起始点和同轮廓的终点相等来判断是否为同一轮廓  size = read(fd, &n_vertices, 4);//一个轮廓环中的点数fprintf(fd_temp,"第%d个轮廓环中的点数=%d\r\n",i+1,n_vertices);size = read(fd, &n_gaps, 4);contour.clear();//删除容器中的所有元素for(j=0;j<n_vertices;j++){size = read(fd, &n_polylineX, 4);fprintf(fd_temp,"{%.0f,",(n_polylineX-minx)*10); //偏移后的坐标放大,保存调试数据到文件size = read(fd, &n_polylineY, 4);fprintf(fd_temp,"%.0f}\r\n",(n_polylineY-miny)*10); //偏移后的坐标放大,保存调试数据到文件contour.push_back(Point((long)((n_polylineX-minx)*10),(long)((n_polylineY-miny)*10))); //向轮廓坐标尾部添加点坐标}v_contour.push_back(contour);//追加当前轮廓数据到当前层容器变量中contour.clear();//删除容器中的所有元素        }////通过冒泡法实现容器中轮廓的排序,使得较小轮廓始终位于较大轮廓后,能够判断是否出现交叉异常(注:两个分离的轮廓也会进行排序,不影响填充)int n; //需要排序的轮廓个数n=v_contour.size();//获取轮廓的个数for(size_t cmpnum = n-1; cmpnum != 0; --cmpnum){for (size_t i = 0; i != cmpnum; ++i){ for(size_t k=0;k<v_contour[i+1].size();k++){flag_swap=pointPolygonTest(v_contour[i], v_contour[i+1][k], false); // 对于每个点都去检测 flag_swap_vector.push_back(flag_swap);}for(size_t z=0;z<flag_swap_vector.size()-1;z++){if(flag_swap_vector[z]!=flag_swap_vector[z+1]){printf("有存在交叉现象\r\n");//这里应该去做相应的异常处理}}flag_swap_vector.clear();//删除容器中的所有元素if (flag_swap == -1){swap(v_contour[i],v_contour[i+1]);}}}//       //清除图像dst.setTo(Scalar(0));//把像素点值清零for(i=0;i<n_boundary;i++)   //把同一层多个轮廓都放在同一容器中,{                           //显示跟数据处理时 要根据起始点和同轮廓的终点相等来判断是否为同一轮廓  d = 0;for (size_t j = 0; j < v_contour[i].size()-1; j++){d += -0.5*(v_contour[i][j+1].y+v_contour[i][j].y)*(v_contour[i][j+1].x-v_contour[i][j].x);}// a) 存放单通道图像中像素:cvScalar(255);// b) 存放三通道图像中像素:cvScalar(255,255,255);if(d > 0){//cout << "逆时针:counterclockwise"<< endl;fprintf(fd_temp,"逆时\r\n\r\n");//填充白色color=cvScalar(255);}else{//cout << "顺时针:clockwise" << endl;fprintf(fd_temp,"顺时\r\n\r\n");//填充黑色color=cvScalar(0);}  drawContours( dst,v_contour ,i, color, CV_FILLED );     }while(!file_continue_flag);file_continue_flag = 0;    // 使下次处于一个阻态imwrite("./dst.bmp",dst);v_contour.clear();//删除容器中的所有元素,这里的元素是同一层中所有轮廓数据fprintf(fd_temp,"第%d层\r\n",sss);printf("第%d层\r\n",sss);printf("BMP_OK\r\n"); }fclose(fd_temp);close(fd);
}void *thread_1(void *args)//文件处理
{while(1){//OpenSLC函数一般情况下为阻态OpenSLC("./jcad.slc");printf("解析结束\r\n");while(1);}return NULL;
}void *thread_2(void *args)//外界通信
{/*内容:1、询问是否解除SLC文件解析阻塞,继续生成位图(注:生成BMP位图比较耗时)*/while(1){getchar();file_continue_flag = 1;}return NULL;
}int main(void)
{int ret=0;pthread_t id1,id2;ret=pthread_create(&id1,NULL,thread_1,NULL);//开启线程   if(ret){printf("create pthread error!\n");return -1; }ret=pthread_create(&id2,NULL,thread_2,NULL);//开启线程if(ret){printf("create pthread error!\n");return  -1; }pthread_join(id1,NULL);//等待线程id1执行完毕,这里阻塞。等待该线程执行完毕后,继续执行下面的语句,否则从主程序中退出,意味着该程序结束了,线程也就没有机会执行。pthread_join(id2,NULL);//等待线程id2执行完毕,这里阻塞。等待该线程执行完毕后,继续执行下面的语句,否则从主程序中退出,意味着该程序结束了,线程也就没有机会执行。printf("main over!\n");return 0;
}

软件流程图

读取的第一层图像

QQ交流聊:275577611

基于OpencV的轮廓填充算法在3D打印机中的应用相关推荐

  1. 水漫金山:OpenCV漫水填充算法(Floodfill)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/28261997 作者:毛星云(浅墨) ...

  2. 【OpenCV入门教程之十五】水漫金山:OpenCV漫水填充算法(Floodfill)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/28261997 作者:毛星云(浅墨) ...

  3. 【OpenCV新手教程之十五】水漫金山:OpenCV漫水填充算法(Floodfill)

    本系列文章由@浅墨_毛星云 出品.转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/28261997 作者:毛星云(浅墨) ...

  4. Python-基于OpenCV的轮廓填充 泛洪算法 孔洞填充

    左为原图 右为填充后 针对轮廓填充,我们先要提取图像中的轮廓,在对里面的进行颜色填充,这个我自己也有点分不清楚,他和阈值分割进行填充有什么区别,要是有大佬知道,分享一下,将感激不尽!轮廓填充的方法常用 ...

  5. 基于opencv的裂缝宽度检测算法(计算轮廓最大内切圆算法)

    这里依然是应用在图像分割的场景,在对路面病害中的裂缝进行检测时,通过UNet++图像分割模型我们可以得到裂缝的标注图像,如下图所示. 针对裂缝的图像分割图像,我们仍需进一步的进行图像处理操作,计算裂缝 ...

  6. Python,OpenCV应用轮廓逼近算法,检测对象的形状

    上一篇博客,我们学习了如何利用Python.OpenCV计算轮廓的中心,这一节学习仅运用轮廓的基本属性来检测其形状,三角形,正方形,矩形,五边形,圆. (1)利用轮廓逼近,将曲线上的点数减少为更简单的 ...

  7. opencv漫水填充算法floodfill

    定义 : 漫水填充算法是一种用特定颜色填充连通区域,通过设置像素上下限及连通方式来达到不同的连通效果.漫水填充经常用来标记或分离图像的一部分,以便于对其进行进一步的处理和分析.也可以从输入图像获取掩码 ...

  8. opencv 基础(6):基于OpenCV的轮廓检测

    利用轮廓检测,我们可以检测出目标的边界,并容易地定位.它通常是许多有趣应用,如图像前景提取,简单图像分割,检测和识别. 轮廓线在计算机视觉中的应用 一些非常酷的应用程序已经建立,使用轮廓进行运动检测或 ...

  9. opencv漫水填充算法

    1.定义 使用特定的颜色填充连通区域,通过设置可连通像素的上下限以及连通方式达到不同的填充效果. 2.opencv漫水填充函数 int floodFill(InputOutputArray image ...

最新文章

  1. 全卷积目标检测:FCOS
  2. SAP WM LQ02 为供应商寄售库存去K的时候,如果有Open TO单,则不能成功为物料去K?
  3. 冒泡排序汇总(整数,实数,字符,字符串)
  4. python可以处理什么文件夹_Python处理文件和文件夹的10条命令
  5. 从零开始实现multipart/form-data数据提交
  6. LeetCode 362. 敲击计数器(map)
  7. GraphX的三大图算法
  8. 复制链接到safari浏览器打开_APP应用内嵌h5页面怎么直接打开Safari来访问链接?
  9. spring云化架构迁移 (一)
  10. 小米蓝牙耳机驱动_硬核拆解——小米蓝牙耳机
  11. ubuntu下如何对接斗鱼直播
  12. Tensorflow中axis的理解
  13. iOS/iPhone学习系列、代码教程----~~~持续更新中~~~
  14. Java进阶(七)Set系列集合、Map集合体系
  15. node.js学习总结:node.js的内置模块,模块化,npm与包 express,前后端身份认证 JWT认证机制
  16. Dual Band Wireless-AC 3165无线驱动无法开启wifi
  17. 【Python】批量修改照片日期
  18. 小笨霖英语笔记本七十七
  19. FM调制的FPGA实现(三)
  20. ADDS:在域内或域间复制组成员

热门文章

  1. 计算机桌面工作提醒,如何在电脑桌面显示工作提醒?电脑上有什么好用的桌面工作提醒便签吗...
  2. 计算机控制原理跟自动控制原理,上海交大考研自动控制理论和自动控制原理有什么区..._在职考研_帮考网...
  3. sipML5实现语音信息服务
  4. Mac Git安装、卸载
  5. 移动端按住说话功能实现
  6. 代理模式Proxy——读书笔记
  7. RIGOL示波器上位机程序DEMO v1.0
  8. 程序员从一线城市撤回到老家之后,不妨考虑一下做IT培训
  9. 微信如何批量添加好友?
  10. Ext2文件系统—文件读写