好久没有正经写博客了,前一段时间一直在备考中级项目管理,再加上项目开发只有自己一个人,每天忙的飞起。有闲暇时间也不想写,其中一部分原因也是因为很多简单问题,AI就能回答的很好。而对复杂的问题,也不是一两句话能够写清楚的。所以及时近期自己做了不少功能,能拿出来分享的也比较少。在这3个多月里,做了激光雕刻机的摄像头的定位,还有选择配件。
一个人做的真的累到要死,特别是团队里还没有能够理解自己的,攻克了一个难题也没有了什么成就感,你做出什么别人都觉得是正常的。
撤了那么多废话,其实就想告诉你们,人生事,不思八九,常想一二。
---------------正文分割线-------------
在激光雕刻机里,能雕刻的东西总体有两种元素,一种矢量元素,svg作为代表,一种是位图,png,jpg图片作为代表。
今天就来说一下如何将一张图片转换成gcode,使用激光雕刻机雕刻出来。
对于一张图片的每个像素,只有两种结果一种雕刻,一种事不雕刻。在GCode上表现为G0(不雕刻);G1(雕刻)。在颜色上就是白和黑。
那么我们首先获取一个图片的所有像素数据。一般使用ImageData来描述。
ImageData 描述了图片的每个像素RGBA四个通道,
这个数据会非常大,比如一个300300的图片,那么ImageData的数组长度就是 300 300*4 =360000。 如果是一个500万像素的照片,那就是一个2000万个元素的数组。
那么图片第一个像素的颜色就是
红色值 ImageData[0]
绿色值 ImageData[1]
蓝色值 ImageData[2]
透明值 ImageData[3]
以此类推。 每个值都是0到255
好现在我们拿到了图片上每个像素的颜色,在处理时我们不使用三种颜色,因为雕刻机只有黑和白。所以我们需要将四通道改为一通道,转换为灰色图。虽然这会丢失很多图片信息,但没办法。如果你的雕刻机能够雕刻出彩色的,那这一步就不需要转换为灰色。
转换为灰色后,图片的第一个像素点的灰度值如下:四个元素值相同,范围都是0-255。
灰色值 ImageData[0]
灰色值 ImageData[1]
灰色值 ImageData[2]
透明值 ImageData[3]
0为黑色,255 为白色。
彩色转灰色 有一个公式
Gray=0.299⋅R+0.587⋅G+0.114⋅B
js的函数实现
/**
* 将图像的每个像素转换为灰度
* @param {HTMLImageElement} image - 要转换的图像
* @param {HTMLCanvasElement} canvas - 目标 canvas 元素
*/
function convertImageToGrayscale(image, canvas) {
const ctx = canvas.getContext('2d');
// 将图像绘制到 canvas 上
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0);
// 获取图像的像素数据
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// 遍历每个像素(每个像素由4个分量组成:R、G、B、A)
for (let i = 0; i < data.length; i += 4) {
const r = data[i]; // 红色通道
const g = data[i + 1]; // 绿色通道
const b = data[i + 2]; // 蓝色通道
// 计算灰度值(加权公式)
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
// 将 R、G、B 替换为灰度值,A 保持不变
data[i] = data[i + 1] = data[i + 2] = gray;
}
// 将灰度图像数据放回 canvas
ctx.putImageData(imageData, 0, 0);
}
好现在你得到了一个灰度图,除去透明度,(这个确实没办法,你总不能激光能够雕刻出透明的效果来。)一张图片的所有像素就变成了一个一维数组来描述。每个元素的值为0-255。那么怎么规定哪些像素该雕刻,哪些像素不雕刻。0-255 的中间值是 128。 这个就是阈值。
小于128的像素我们就雕刻变成黑色,
大于128的像素我们就不雕刻,保持材料原来的颜色。
黑白图也是这样的来的。
下面我给你看一下原图,灰度图,黑白图的区别。
上面这个是原图,我最近在做的旋转配件测试。
把这图片进行灰度化后就变成了下面的效果
上面的就是灰色图,这让我想起了小时候家里的黑白电视。
当我们将0-255的灰色通过阈值128 处理后,就变成了只有0和255的两值图片,真正的黑白照片,只有黑白。下面的就是黑白图片,会都是很多细节。
到了这里你就已经能够雕刻出图片啦,虽然会丢失很多细节。那么接下来就要思考 如何在只有黑白两种颜色的情况下尽可能多地展示图片的细节?
我在这里也卡了很久,通过查阅资料 得知了抖动这一图片算法。它的原理是在使用一个卷积 ,将灰度值的误差扩散到相邻的几个像素上。增一下一些黑色的小白点,我们可以把它叫做噪点,它会欺骗我们的眼睛,让我们觉得图片会不同层次的灰度。增加噪点的规律是 在特别黑的地方,越黑的地方早点增加的越多,越白的地方噪点越少。
灰度值的误差是这样计算的, 比如当前像素的灰度值是200,那么它应该转换为255,误差是55,将这个误差55,加到相邻的上下左右的像素上。
经典抖动卷积核
X 7/16
3/16 5/16 1/16
X 代表当前像素(当前位置)。
右边和下面的像素接收当前像素的误差,权重之和为 1。
公式的含义是将当前像素的“误差”分配到相邻像素,以在视觉上减少色彩深度丢失的影响。
下面看一下经过抖动算法处理的图片
虽然上面的图片也只有黑白两个颜色,但是和灰度图表现的细节相差无几。
整体看下四个图片
另一个例子
最终的雕刻效果(自己去试吧,雕刻图片会吸不少甲醛)
获取到了抖动图后,后面就比较简单了,就是遍历数组,数组的元素 只有两个值0 和255。
遇到0 就用G1,遇到255 就用G0
最终形成了图片的GCode
如果有人对图片GCode,位图转GCode,雕刻图片感兴趣的话,后面再写一个优化图片GCode,双向雕刻,过滤白色行,相对路径雕刻图片。
今天这篇文章就写到这里啦。
最后就是 我的项目管理考试过了,哈哈 不枉我复习了2个月多,每天背着600多页的书。