基于二值化图像转GCode的斜向扫描实现

news2024/9/22 15:47:57
  • 基于二值化图像转GCode的斜向扫描实现
    • 什么是斜向扫描
    • 斜向扫描代码示例

基于二值化图像转GCode的斜向扫描实现

什么是斜向扫描

激光雕刻斜向扫描

在激光雕刻中,斜向扫描(Diagonal Scanning)是一种雕刻技术,其中激光头沿着对角线方向来回移动,而不是沿着水平或垂直方向。这种扫描方式的目的是在雕刻过程中更均匀地覆盖整个图像表面,从而提高雕刻的效果。

斜向扫描的过程包括以下步骤:

  1. 起始位置: 激光头移动到图像的起始位置。

  2. 斜向移动: 激光头沿对角线方向开始移动,逐行或逐列地刻蚀图像表面。与水平或垂直扫描不同,激光头沿着斜线移动,使得刻蚀路径更加均匀。

  3. 返回: 当一行或一列刻蚀完成后,激光头返回到图像的另一侧,准备进行下一行或下一列的刻蚀。

  4. 循环重复: 重复以上步骤,直到整个图像都被刻蚀完成。

相比于传统的水平或垂直扫描,斜向扫描能够减少在图像表面上可能出现的痕迹或线条,使得雕刻效果更为平滑和均匀。这对于一些需要高质量表面的雕刻应用,如艺术品或装饰品制作,具有重要意义。

选择采用斜向扫描还是其他扫描方式通常取决于具体的雕刻需求和设计目标。一些激光雕刻机允许用户根据实际情况选择不同的扫描方式以获得最佳的雕刻效果。

斜向扫描代码示例

#include <optional>
#include <string>
#include <print>
#include <format>
#include <vector>
#include <fstream>
#include <ranges>

struct G0 {
    std::optional<float> x, y;
    std::optional<int> s;

    std::string toString() {
        std::string command = "G0";
        if(x.has_value()) {
            command += std::format(" X{:.3f}", x.value());
        }
        if(y.has_value()) {
            command += std::format(" Y{:.3f}", y.value());
        }
        if(s.has_value()) {
            command += std::format(" S{:d}", s.value());
        }
        return command;
    }

    explicit operator std::string() const {
        std::string command = "G0";
        if(x.has_value()) {
            command += std::format(" X{:.3f}", x.value());
        }
        if(y.has_value()) {
            command += std::format(" Y{:.3f}", y.value());
        }
        if(s.has_value()) {
            command += std::format(" S{:d}", s.value());
        }
        return command;
    }
};

struct G1 {
    std::optional<float> x, y;
    std::optional<int> s;

    std::string toString() {
        std::string command = "G1";
        if(x.has_value()) {
            command += std::format(" X{:.3f}", x.value());
        }
        if(y.has_value()) {
            command += std::format(" Y{:.3f}", y.value());
        }
        if(s.has_value()) {
            command += std::format(" S{:d}", s.value());
        }
        return command;
    }

    explicit operator std::string() const {
        std::string command = "G1";
        if(x.has_value()) {
            command += std::format(" X{:.3f}", x.value());
        }
        if(y.has_value()) {
            command += std::format(" Y{:.3f}", y.value());
        }
        if(s.has_value()) {
            command += std::format(" S{:d}", s.value());
        }
        return command;
    }
};

inline bool ExportGCode(const std::string &fileName, std::vector<std::string> &&gcode) {
    std::fstream file;
    file.open(fileName, std::ios_base::out | std::ios_base::trunc);
    if(!file.is_open()) {
        return false;
    }

    for(auto &&v: gcode | std::views::transform([](auto item) { return item += "\n"; })) {
        file.write(v.c_str(), v.length());
    }

    return true;
}

int main() {
    constexpr int imageWidth  = 10;
    constexpr int imageHeight = 10;
    // clang-format off
    // 假设图像数据,0表示非激光刻蚀部分,1表示进行激光刻蚀的区域
    constexpr int image[imageWidth][imageHeight] = {
        {0, 1, 1, 1, 0, 1, 1, 1, 0, 0}, // G0 G1 G1 G1 G0 G1 G1 G1 G0 G0
        {1, 0, 1, 0, 1, 0, 1, 0, 1, 0},
        {1, 1, 1, 0, 0, 1, 1, 1, 1, 1},
        {0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {1, 1, 0, 0, 1, 0, 0, 1, 1, 1},
        {0, 1, 1, 0, 0, 1, 0, 0, 0, 0},
        {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
        {1, 0, 0, 0, 1, 0, 1, 0, 0, 0},
        {0, 1, 0, 1, 0, 1, 0, 1, 0, 1},
        {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
    };
    // clang-format on

    std::vector<std::string> command;
   for(int k = 0; k < imageHeight + imageWidth - 1 /*cond = height + width - 1*/; ++k) {  // 线条数
        if constexpr (false) {
            // 单斜向
            for(int x = std::min(k, imageHeight - 1); x >= 0; --x) {
                int y = k - x;
                if(y < imageWidth) {
                    if(auto const value = image[y][x];value) {
                        command.emplace_back(G1 {x, y, 1000});  // 最大激光功率 S=1000
                    } else {
                        command.emplace_back(G0 {x, y, 0});
                    }
                }
            }
        }else {
            // 双斜向
            if((k & 1) == 0) {
                // even
                for(int x = std::min(k, imageHeight - 1); x >= 0; --x) {
                    int y = k - x;
                    if(x < imageHeight && y < imageWidth) {
                        if(auto const value = image[y][x];value) {
                            command.emplace_back(G1 {x, y, 1000});  // 最大激光功率 S=1000
                        } else {
                            command.emplace_back(G0 {x, y, 0});
                        }
                    }
                }
            }else {
                // odd
                for(int y = std::min(k, imageWidth - 1); y >= 0; --y) {
                    int x = k - y;
                    if(x < imageHeight && y < imageWidth) {
                        if(auto const value = image[y][x];value) {
                            command.emplace_back(G1 {x, y, 1000});  // 最大激光功率 S=1000
                        } else {
                            command.emplace_back(G0 {x, y, 0});
                        }
                    }
                }
            }
        }
    }
    
    // 导出GCode
    ExportGCode("gcode.nc",std::move(command));
    std::println("Export data to gcode.nc");
    return 0;
}

单向斜向扫描
激光雕刻单斜向扫描

双向斜向扫描
激光雕刻双斜向扫描仿真

上述示例展示了一个10x10的二维图像数据,其中0表示非激光刻蚀部分,1表示进行激光刻蚀的区域。通过遍历图像数据,代码生成了相应的G代码指令序列,用于描述激光头在工件表面的运动路径。

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

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

相关文章

上位机图像处理和嵌入式模块部署(视频处理vs图像处理)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 从目前发展的情况来看&#xff0c;视频处理会慢慢变成一种主流趋势。这里面的原因很多&#xff0c;比如说现在嵌入式soc的算力越来越强、获取图像的…

【大数据安全】大数据安全的挑战与对策基础设施安全

目录 一、大数据安全的挑战与对策 &#xff08;一&#xff09;数据加密技术 &#xff08;二&#xff09;大数据安全与隐私 &#xff08;三&#xff09;大数据安全保障体系 &#xff08;四&#xff09;华为大数据安全解决方案 二、基础设施安全 &#xff08;一&#xff0…

TSINGSEE青犀视频智慧电梯管理平台,执行精准管理、提升乘梯安全

一、方案背景 随着城市化进程的不断加快&#xff0c;我国已经成为全球最大的电梯生产和消费市场&#xff0c;电梯也成为人们日常生活中不可或缺的一部分。随着电梯数量的激增&#xff0c;电梯老龄化&#xff0c;维保数据不透明&#xff0c;物业管理成本高&#xff0c;政府监管…

用React给XXL-JOB开发一个新皮肤(四):实现用户管理模块

目录 一. 简述二. 模块规划 2.1. 页面规划2.2. 模型实体定义 三. 模块实现 3.1. 用户分页搜索3.2. Modal 配置3.3. 创建用户表单3.4. 修改用户表单3.5. 删除 四. 结束语 一. 简述 上一篇文章我们实现登录页面和管理页面的 Layout 骨架&#xff0c;并对接登录和登出接口。这篇…

【代码随想录】刷题笔记Day56

前言 26回了老家参加二姨的婚礼&#xff0c;还逛了几圈亲戚&#xff0c;回来就接家教的活&#xff0c;想到还要刷题开组会&#xff0c;回家注定是没法怎么休息啦&#xff0c;可恶 42. 接雨水 - 力扣&#xff08;LeetCode&#xff09; 暴力解法&#xff08;双指针优化&#xf…

SpringBoot中集成Minio高性能分布式存储文件服务入门

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目-CSDN博客 参考上面搭建项目。 Minio Minio是基于Go语言编写的对象存储服务&#xff0c;适合于存储大容量非结构化的数据&#xff0c;例如图片、音频…

定制自己的linux

记得看目录哦&#xff01; 1. 基本介绍2. 思路分析3. 开始定制3.1 添加一块20G的硬盘3.2 重启&#xff0c;进行磁盘分区3.3 格式化分区3.4 创建目录&#xff0c;并挂载磁盘3.5 安装grub3.6 看是否安装上3.7 内核文件拷贝到磁盘3.8 修改grub2/grub.cfg3.9 创建目标主机的根文件系…

Spring Boot项目中集成连接池及部分细节说明

连接池 一&#xff0c;Connection连接二&#xff0c;数据库连接池三&#xff0c;集成数据库连接池1&#xff0c;Spring Boot默认连接池2&#xff0c;Druid连接池3&#xff0c;集成Druid&#xff08;原生版本&#xff09;3.1&#xff0c;引入依赖3.2&#xff0c;配置数据源3.3&a…

CSS 实现立体字效果

我们在工作中&#xff0c;很多场景会遇到立体文字&#xff0c;今天我们就来实现下&#xff0c;很简单&#xff0c;算是水文章吧&#xff1a; <h1>立体字体</h1>h1 {margin: 100px 0 0 100px;font-size: 5em;color: #fff;text-shadow: -1px 1px #bbb,-2px 2px #bbb…

设计模式——职责链模式(Chain of Responsibility Pattern)

概述 职责链模式(Chain of Responsibility Pattern)&#xff1a;避免请求发送者与接收者耦合在一起&#xff0c;让多个对象都有可能接收请求&#xff0c;将这些对象连接成一条链&#xff0c;并且沿着这条链传递请求&#xff0c;直到有对象处理它为止。职责链模式是一种对象行为…

深度学习(9)--pydot库和graphviz库安装流程详解

目录 一.pydot库安装 二.graphviz库安装 一.pydot库安装 pydot的安装可直接在编译器安装相关包&#xff0c;以PyCharm举例&#xff1a; 如果搜索可用软件包显示为空&#xff0c;记得在此处把使用Conda软件包管理器”点亮 二.graphviz库安装 点击链接下载安装包graphviz-2.38…

DX-11A DC0.075A 型信号继电器 柜内安装,板前接线

DX-11信号继电器&#xff1b; DX-11A信号继电器&#xff1b; DX-11B信号继电器&#xff1b; DX-11C信号继电器&#xff1b; DX-11Q信号继电器&#xff1b; DX-11A/Q信号继电器&#xff1b; DX-11B/Q信号继电器&#xff1b; DX-11C/Q信号继电器&#xff1b; 一. 用途 DX-11/0.…

.net core 6 集成 elasticsearch 并 使用分词器

1、nuget包安装NEST、安装elasticsearch、kibana、ik分词器、拼音分词器 2、创建操作对象 //索引库 static string indexName "testparticper"; //es 操作对象 ElasticClient elasticClient new ElasticClient(new ConnectionSettings(new Uri("http://192.…

Python使用分治算法作归并排序

对于分治算法的一个较为常规的应用中&#xff0c;归并排序是一个使用分治算法的排序方式。给定一个随机排序的数组&#xff0c;我们要将其元素按照升序或者降序的方式进行排序&#xff0c;可以设想到这样的一种算法&#xff0c;如果一个数组的上半部分和下半部分已经排好序&…

(HAL)STM32F407ZGT6——10-4 高级定时器 PWM 输入模式实验

一、高级定时器简介 高级定时器的框图和通用定时器框图很类似&#xff0c;只是添加了其它的一些功能&#xff0c;如&#xff1a;重复计数器、带死区控制的互补输出通道、断路输入等。 高级定时器的时钟来自APB2, 而PCLK2 168Mhz, 我们设置PPRE2不分频, 因此高级定时器时钟 …

如何通过Hive/tez与Hadoop的整合快速实现大数据开发

一、Hive的功能 Hive是基于Hadoop的一个外围数据仓库分析组件&#xff0c;可以把Hive理解为一个数据仓库&#xff0c;但这和传统的数据库是有差别的。 传统数据库是面向业务存储&#xff0c;比如 OA、ERP 等系统使用的数据库&#xff0c;而数据仓库是为分析数据而设计的。同时…

05 MyBatis之表关系的声明+事务+SqlSession三件套的作用域

MyBatis 支持一对一&#xff0c;一对多&#xff0c;多对多查询。XML 文件和注解都能实现关系的操作。多对多实质就是一对多 1. 表关系的维护 1.1 One一对一 一对一查询和多表(两表)查询很相似, 都能查询两表的全部属性 区别是一对一可以在对象中嵌套对象, 呈现包含关系; 多表…

Kotlin快速入门系列9

Kotlin对象表达式和对象声明 对象表达式 有时&#xff0c;我们想要创建一个对当前类有些许修改的对象同时又不想重新声明一个子类。如果是Java&#xff0c;可以用匿名内部类的概念来解决这个问题。kotlin的对象表达式和对象声明就是为了实现这一点(创建一个对某个类做了轻微改…

Java 开发环境 全套包含IDEA

一、JDK配置 1.下载 JDK Builds from Oracle 去这边下载open JDK 2.JDK环境变量配置 按win&#xff0c;打开设置 找到环境变量编辑 这边输入的是你下载的那个JDK的bin的路径 检擦配置是否正确在cmd中输入 二、IDEA安装配置 1.下载&#xff08;社区版&#xff09; JetBrai…

干货 | 大模型在图数据分析、推荐系统和生物科学中的综合应用

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 图机器学习、推荐系统与大语言模型的融合正成为新的前沿热点。图机器学习通过利用图结构数据&#xff0c;能够有效地捕捉和分析复杂关系和模式。同时&#xff0c;推荐系统正逐步成为我们日常生活的一部分&#…