最近项目需要控制雕刻机进行雕刻图案,所以要把图片转成机器所能识别的GCode码,研究了几天,需要使用OpenCV来处理,这篇文章和大家分享。
第一步 配置OpenCV环境
iOS集成OpenCV有两种方式,第一种使用cocoapods(本文使用),第二种是自己手动导入。
1.使用 cocoapods 导入openCV2库
pod 'OpenCV2'
注意:此处导入的是OpenCV2,不是OpenCV,我先pod OpenCV,结果编译报错,网上查阅资料让pod OpenCV2,原因是由于OpenCV库太老,会导致很多文件名重复 从而编译失败。
2.创建需要使用OpenCV的文件
3.需要将.m文件改为.mm
4.需要将.h和.mm文件的 Identity and Type 中的Type 选择 Objective C ++ Source
5.导入OpenVC的头文件
注意:需要在导入所有头文件前导入OpenVC的头文件,并且需要开头加上 #ifdef __cplusplus,结尾加上 #endif
#ifdef __cplusplus
#import <opencv2/opencv.hpp>
#import <opencv2/highgui/highgui.hpp>
#import <opencv2/imgcodecs/ios.h>
#import <opencv2/imgproc/types_c.h>
#import <opencv2/imgproc.hpp>
#import <opencv2/core/core.hpp>
#import <iostream>
#import <vector>
#import <iosfwd>
#import <ios>
#import <fstream>
#endif
6.targets ->Build Phases->link binary中加入一下库:
libc++.tbd
第二步 写相关OpenCV代码
.h文件代码如下:
@interface LYImageToGCode : NSObject
+ (void)Image2GcodeFromImage:(UIImage *)image;
@end
.m文件代码如下:
#import "LYImageToGCode.h"
using namespace cv;
using namespace std;
bool isG0Mode = true;
uint32_t StringLen = 0;
float quality;
uchar* gData;
char x_ValueString[10], y_ValueString[10], s_ValueString[10];
volatile uint16_t yLast = 0xFFFF;
float matrix[3][4]{
{0, 0, 1.0 / 8, 1.0 / 8},
{1.0 / 8, 1.0 / 8, 1.0 / 8, 0},
{0, 1.0 / 8, 0, 0}
};
@implementation LYImageToGCode
void image_atkinson(Mat &srcImg)
{
cv::Mat img;
cv::cvtColor(srcImg, img, COLOR_GRAY2BGRA);
const int matrixHeight = 3;
const int matrixWidth = 4;
int matrixOffset = 0;
for (int k = 1; k < matrixWidth; k++) {
if (matrix[0][k] > 0.0) {
matrixOffset = k - 1;
break;
}
}
double f_data = 0;
uchar *pimgdata = img.ptr<uchar>(0);
for (int y = 0; y < img.rows; y++) {
const int reverse = (y & 1);
for (int x = reverse ? img.cols - 1 : 0; reverse ? x >= 0 : x < img.cols; reverse ? x-- : x++) {
const int index = (y * img.cols + x) << 2;
const int origin = pimgdata[index];
pimgdata[index] = origin > 127 ? 255 : 0;
pimgdata[index + 1] = pimgdata[index];
pimgdata[index + 2] = pimgdata[index];
const int err = origin - pimgdata[index];
for (int i = 0; i < matrixWidth; i++) {
for (int j = 0; j < matrixHeight; j++) {
if (matrix[j][i] > 0) {
const int x2 = reverse ? x - (i - matrixOffset) : x + (i - matrixOffset);
const int y2 = y + j;
if (x2 >= 0 && x2 < img.cols && y2 < img.rows) {
const int idx2 = index + ((x2 - x) << 2) + (y2 - y) * (img.cols << 2);
f_data = matrix[j][i] * err + pimgdata[idx2];
f_data = (f_data < 0) ? 0 : ((f_data > 255) ? 255 : f_data);
pimgdata[idx2] = (f_data + 0.5);
}
}
}
}
}
}
cv::cvtColor(img, srcImg, COLOR_BGRA2GRAY);
}
uint32_t float2string(uint32_t f, uint32_t p, char* s)
{
uint32_t fi = p * f / quality + 0.5;
memset(s, 0, 8);
if (fi == 0)
{
s[0] = '0';
return 1;
}
while (p > 1)
{
if (fi % 10)
{
break;
}
fi /= 10;
p /= 10;
}
if (fi >= 100000)
{
s[0] = fi / 100000 + 0x30;
s[1] = fi / 10000 % 10 + 0x30;
s[2] = fi / 1000 % 10 + 0x30;
s[3] = '.';
s[4] = fi / 100 % 10 + 0x30;
s[5] = fi / 10 % 10 + 0x30;
s[6] = fi % 10 + 0x30;
return 7;
}
else if (fi >= 10000)
{
if (p == 1000)
{
s[0] = fi / 10000 + 0x30;
s[1] = fi / 1000 % 10 + 0x30;
s[2] = '.';
s[3] = fi / 100 % 10 + 0x30;
s[4] = fi / 10 % 10 + 0x30;
s[5] = fi % 10 + 0x30;
return 6;
}
else
{
s[0] = fi / 10000 + 0x30;
s[1] = fi / 1000 % 10 + 0x30;
s[2] = fi / 100 % 10 + 0x30;
s[3] = '.';
s[4] = fi / 10 % 10 + 0x30;
s[5] = fi % 10 + 0x30;
return 6;
}
}
else if (fi >= 1000)
{
if (p == 1000)
{
s[0] = fi / 1000 + 0x30;
s[1] = '.';
s[2] = fi / 100 % 10 + 0x30;
s[3] = fi / 10 % 10 + 0x30;
s[4] = fi % 10 + 0x30;
return 5;
}
else if (p == 100)
{
s[0] = fi / 1000 + 0x30;
s[1] = fi / 100 % 10 + 0x30;
s[2] = '.';
s[3] = fi / 10 % 10 + 0x30;
s[4] = fi % 10 + 0x30;
return 5;
}
else
{
s[0] = fi / 1000 + 0x30;
s[1] = fi / 100 % 10 + 0x30;
s[2] = fi / 10 % 10 + 0x30;
s[3] = '.';
s[4] = fi % 10 + 0x30;
return 5;
}
}
else if (fi >= 100)
{
if (p == 1000)
{
s[0] = '0';
s[1] = '.';
s[2] = fi / 100 + 0x30;
s[3] = fi / 10 % 10 + 0x30;
s[4] = fi % 10 + 0x30;
return 5;
}
else if (p == 100)
{
s[0] = fi / 100 + 0x30;
s[1] = '.';
s[2] = fi / 10 % 10 + 0x30;
s[3] = fi % 10 + 0x30;
return 4;
}
else if (p == 10)
{
s[0] = fi / 100 + 0x30;
s[1] = fi / 10 % 10 + 0x30;
s[2] = '.';
s[3] = fi % 10 + 0x30;
return 4;
}
else
{
s[0] = fi / 100 + 0x30;
s[1] = fi / 10 % 10 + 0x30;
s[2] = fi % 10 + 0x30;
return 3;
}
}
else if (fi >= 10)
{
if (p == 1000)
{
s[0] = '0';
s[1] = '.';
s[2] = '0';
s[3] = fi / 10 + 0x30;
s[4] = fi % 10 + 0x30;
return 5;
}
else if (p == 100)
{
s[0] = '0';
s[1] = '.';
s[2] = fi / 10 + 0x30;
s[3] = fi % 10 + 0x30;
return 4;
}
else if (p == 10)
{
s[0] = fi / 10 + 0x30;
s[1] = '.';
s[2] = fi % 10 + 0x30;
return 3;
}
else
{
s[0] = fi / 10 + 0x30;
s[1] = fi % 10 + 0x30;
return 2;
}
}
else
{
if (p == 1000)
{
s[0] = '0';
s[1] = '.';
s[2] = '0';
s[3] = '0';
s[4] = fi + 0x30;
return 5;
}
else if (p == 100)
{
s[0] = '0';
s[1] = '.';
s[2] = '0';
s[3] = fi + 0x30;
return 4;
}
else if (p == 10)
{
s[0] = '0';
s[1] = '.';
s[2] = fi + 0x30;
return 3;
}
else
{
s[0] = fi + 0x30;
return 1;
}
}
}
uint32_t int2string(uint32_t d, char* s)
{
memset(s, 0, 5);
if (d >= 1000)
{
s[0] = d / 1000 + 0x30;
s[1] = d / 100 % 10 + 0x30;
s[2] = d / 10 % 10 + 0x30;
s[3] = d % 10 + 0x30;
return 4;
}
else if (d >= 100)
{
s[0] = d / 100 + 0x30;
s[1] = d / 10 % 10 + 0x30;
s[2] = d % 10 + 0x30;
return 3;
}
else if (d >= 10)
{
s[0] = d / 10 + 0x30;
s[1] = d % 10 + 0x30;
return 2;
}
else
{
s[0] = d + 0x30;
return 1;
}
}
int string2int(char* str, int len)
{
if (len == 1)
{
return str[0] - 0x30;
}
else if (len == 2)
{
return (str[0] - 0x30) * 10 + str[1] - 0x30;
}
else if (len == 3)
{
return (str[0] - 0x30) * 100 + (str[1] - 0x30) * 10 + str[2] - 0x30;
}
else
{
return 0;
}
}
float string2float(char* str, int len)
{
if (len == 1)
{
return (str[0] - 0x30) * 0.1;
}
else if (len == 2)
{
return (str[0] - 0x30) * 0.1 + (str[1] - 0x30) * 0.01;
}
else if (len == 3)
{
return (str[0] - 0x30) * 0.1 + (str[1] - 0x30) * 0.01 + (str[2] - 0x30) * 0.001;
}
else
{
return 0;
}
}
void WriteGcodeString(uint32_t x, uint32_t y, uint32_t s)
{
if (s != 0)
{
if (isG0Mode)
{
memcpy(gData, "G1 ", 3);
gData += 3;
isG0Mode = false;
}
memcpy(gData, "X", 1);
gData += 1;
StringLen = float2string(x, 1000, x_ValueString);
memcpy(gData, x_ValueString, StringLen);
gData += StringLen;
memcpy(gData, " S", 2);
gData += 2;
StringLen = int2string(s, s_ValueString);
memcpy(gData, s_ValueString, StringLen);
gData += StringLen;
memcpy(gData, "\n", 1);
gData += 1;
}
else
{
isG0Mode = true;
memcpy(gData, "G0 X", 4);
gData += 4;
StringLen = float2string(x, 1000, x_ValueString);
memcpy(gData, x_ValueString, StringLen);
gData += StringLen;
memcpy(gData, " Y", 2);
gData += 2;
StringLen = float2string(y, 1000, y_ValueString);
memcpy(gData, y_ValueString, StringLen);
gData += StringLen;
memcpy(gData, " S0\n", 4);
gData += 4;
}
}
void GcodeCompress(char* gCodeBuffer, uint8_t* dataCompress, uint16_t sValue, uint16_t speed, bool isHead, string savePath)
{
uint8_t numLen = 0;
uint16_t x, y, xf, yf;
uint8_t* head = dataCompress;
if (isHead) {
*dataCompress++ = 0xEE;
*dataCompress++ = 0xFF;
*dataCompress++ = sValue;
*dataCompress++ = sValue >> 8;
*dataCompress++ = speed;
*dataCompress++ = speed >> 8;
char* fid = new char[80]();
char* fidHead = fid;
int idMax = quality - 1;
for (int i = 0; i < idMax; i++)
{
fid[0] = float2string(i + 1, 1000, x_ValueString) - 2;
memcpy(&fid[1], &x_ValueString[2], fid[0]);
fid += 4;
}
memcpy(dataCompress, fidHead, 80);
dataCompress += 80;
dataCompress += 42;
}
while (gCodeBuffer[0] != 0)
{
if(gCodeBuffer[1]=='1')
{
gCodeBuffer += 4;
numLen = 0;
while (gCodeBuffer[0] != '.' && gCodeBuffer[0] != ' ')
{
gCodeBuffer++;
numLen++;
}
x = (string2int(gCodeBuffer - numLen, numLen)) << 5;
if (gCodeBuffer[0] == '.')
{
numLen = 0;
gCodeBuffer++;
while (gCodeBuffer[0] != ' ')
{
gCodeBuffer++;
numLen++;
}
x += (string2float(gCodeBuffer - numLen, numLen) * quality + 0.5);
}
x |= 0x8000;
memcpy(dataCompress, &x, 2);
dataCompress += 2;
}
else if (gCodeBuffer[1] == '0')
{
gCodeBuffer += 4;
numLen = 0;
while (gCodeBuffer[0] != '.' && gCodeBuffer[0] != ' ')
{
gCodeBuffer++;
numLen++;
}
x = (string2int(gCodeBuffer - numLen, numLen)) << 5;
if (gCodeBuffer[0] == '.')
{
numLen = 0;
gCodeBuffer++;
while (gCodeBuffer[0] != ' ')
{
gCodeBuffer++;
numLen++;
}
x += (string2float(gCodeBuffer - numLen, numLen) * quality + 0.5);
}
while (*gCodeBuffer++ != 'Y');
numLen = 0;
while (gCodeBuffer[0] != '.' && gCodeBuffer[0] != ' ')
{
gCodeBuffer++;
numLen++;
}
y = (string2int(gCodeBuffer - numLen, numLen)) << 5;
if (gCodeBuffer[0] == '.')
{
numLen = 0;
gCodeBuffer++;
while (gCodeBuffer[0] != ' ')
{
gCodeBuffer++;
numLen++;
}
y += (string2float(gCodeBuffer - numLen, numLen) * quality + 0.5);
}
if (y != yLast)
{
yLast = y;
x |= 0x4000;
memcpy(dataCompress, &x, 2);
dataCompress += 2;
memcpy(dataCompress, &y, 2);
dataCompress += 2;
}
else
{
memcpy(dataCompress, &x, 2);
dataCompress += 2;
}
}
while (*gCodeBuffer++ != '\n');
}
ofstream ff;
if(isHead)
ff.open(savePath + ".bin", ios::out | ios::binary);
else
ff.open(savePath + ".bin", ios::out | ios::app | ios::binary);
ff.write((const char*)head, dataCompress - head);
ff.flush();
ff.close();
}
/*
* srcImg:openCV图像
* linePerMillimetre:每毫米(mm)多少行,即PC端软件的“质量”,范围1~20
* engraveWidth、engraveHeight,最终雕刻成品大小,单位毫米(mm)
* sMax:S最大值,即激光最大功率,范围1~1000
* isLineToLine:即PC软件的线到线处理,不做灰度抖动
* compressed: 是否压缩Gcode
*/
void ImageToGCodeOpenVC(Mat &srcImg, int linePerMillimetre, int engraveWidth, int engraveHeight, int sMax, int speed, bool isLineToLine, bool compressed, string savePath)
{
Mat M1 = srcImg;
Mat M2;
resize(M1, M2, cv::Size(M1.cols * linePerMillimetre * engraveHeight / M1.rows, linePerMillimetre * engraveHeight), 0, 0, INTER_CUBIC);
quality = linePerMillimetre * 1.0;
if (isLineToLine == false)
{
image_atkinson(M2);
}
M2 = 255 - M2;
flip(M2, M2, 0);
uchar *imgdata = (uchar*)M2.data;
uchar* gDataHead = new uchar[1024 * 1024 * 1]();
gData = gDataHead;
uchar* cDataHead = new uchar[1024 * 1024 * 1]();
uchar* cData = cDataHead;
bool ishead = true;
ofstream f;
f.open(savePath, ios::out);
f << "G90" << endl;
f << "G0 X0 Y0 F" << speed << endl;
f << "M3 S0" << endl;
uint32_t x_Value = 0, y_Value = 0, s_Value = 0;
uint32_t cacheLen = 0;
for (int h = 0; h < M2.rows; h++)
{
const int reverse = (h & 1);
x_Value = reverse ? M2.cols : 0;
for (int w = reverse ? M2.cols - 1 : 0; reverse ? w > 0 : w < M2.cols; reverse ? w-- : w++)
{
if (isG0Mode == false && imgdata[h*M2.cols + w] != 0)
{
WriteGcodeString(x_Value, y_Value, 0);
}
x_Value = reverse ? x_Value - 1 : x_Value + 1;
if (imgdata[h*M2.cols + w] != imgdata[h*M2.cols + (reverse ? (w - 1) : (w + 1))])
{
s_Value = sMax * imgdata[h*M2.cols + w] / 255;
WriteGcodeString(x_Value, y_Value, s_Value);
cacheLen++;
}
if (((w == M2.cols - 2) && (reverse == 0)) || ((w == 1) && (reverse != 0)))
{
y_Value += 1;
x_Value = reverse ? 0 : M2.cols;
if (imgdata[h*M2.cols + (reverse ? (w - 1) : (w + 1))] != 0)
{
s_Value = sMax * imgdata[h*M2.cols + (reverse ? (w - 1) : (w + 1))] / 255;
WriteGcodeString(x_Value, y_Value, s_Value);
cacheLen += 2;
}
break;
}
if (cacheLen > 30000)
{
cacheLen = 0;
f << gDataHead;
f.flush();
if(compressed)
{
GcodeCompress((char*)gDataHead, cDataHead, sMax, speed, ishead, savePath);
if (ishead)
{
ishead = false;
}
memset(cDataHead, 0, 1024 * 1024 * 1);
}
memset(gDataHead, 0, 1024 * 1024 * 1);
gData = gDataHead;
}
}
}
f << gDataHead;
if(compressed)
{
GcodeCompress((char*)gDataHead, cDataHead, sMax, speed, ishead, savePath);
if (ishead)
{
ishead = false;
}
memset(cDataHead, 0, 1024 * 1024 * 1);
}
f << "M5" << endl;
f << "G0 X0 Y0 Z0" << endl;
f.flush();
f.close();
if(compressed)
{
f.open(savePath + ".bin", ios::out | ios::app | ios::binary);
f.write("\xEE\xFF", 2);
f.flush();
f.close();
}
delete []gDataHead;
delete []cDataHead;
}
void WriteGcodeString2(uint32_t x, uint32_t y, int s)
{
if (s != 0)
{
if (isG0Mode)
{
memcpy(gData, "G1 ", 3);
gData += 3;
isG0Mode = false;
}
memcpy(gData, "X", 1);
gData += 1;
StringLen = float2string(x, 1000, x_ValueString);
memcpy(gData, x_ValueString, StringLen);
gData += StringLen;
memcpy(gData, " Y", 2);
gData += 2;
StringLen = float2string(y, 1000, y_ValueString);
memcpy(gData, y_ValueString, StringLen);
gData += StringLen;
memcpy(gData, " S", 2);
gData += 2;
StringLen = int2string(s, s_ValueString);
memcpy(gData, s_ValueString, StringLen);
gData += StringLen;
memcpy(gData, "\n", 1);
gData += 1;
}
else
{
isG0Mode = true;
memcpy(gData, "G0 X", 4);
gData += 4;
StringLen = float2string(x, 1000, x_ValueString);
memcpy(gData, x_ValueString, StringLen);
gData += StringLen;
memcpy(gData, " Y", 2);
gData += 2;
StringLen = float2string(y, 1000, y_ValueString);
memcpy(gData, y_ValueString, StringLen);
gData += StringLen;
memcpy(gData, " S0\n", 4);
gData += 4;
}
}
void bwLabel(const uchar *bw, int *label, int h, int w, int sMax, int speed, string savePath)
{
memset(label, 0, h * w << 2);
int maxComponents = (h * w >> 1) + 1;
int * const link = new int[maxComponents];
int lb = 1, x, y, a, b, t, *p = label;
link[0] = 0;
if (bw[0]) {
p[0] = lb;
link[lb] = lb;
lb++;
}
for (x = 1; x < w; x++) if (bw[x]) {
if (p[x - 1])
p[x] = p[x - 1];
else {
p[x] = lb;
link[lb] = lb;
lb++;
}
}
bw += w, p += w;
for (y = 1; y < h; y++, bw += w, p += w) {
if (bw[0]) {
if (p[-w])
p[0] = p[-w];
else {
p[0] = lb;
link[lb] = lb;
lb++;
}
}
for (x = 1; x < w; x++) if (bw[x]) {
a = p[x - 1], b = p[x - w];
if (a) {
if (a == b)
p[x] = a;
else {
t = a;
while (a != link[a])
a = link[a];
p[x] = link[t] = a;
if (b) {
t = b;
while (b != link[b])
b = link[b];
link[t] = b;
if (a < b) link[b] = a; else link[a] = b;
}
}
}
else if (b) {
t = b;
while (b != link[b])
b = link[b];
p[x] = link[t] = b;
}
else {
p[x] = lb;
link[lb] = lb;
lb++;
}
}
}
t = 1;
for (x = 1; x < lb; x++)
if (x == link[x]) {
link[x] = -t;
t++;
}
for (x = 1; x < lb; x++) {
y = x;
while (link[y] >= 0)
y = link[y];
link[x] = link[y];
}
for (x = 1; x < lb; x++)
link[x] = -link[x];
p = label;
for (y = 0; y < h; y++, p += w)
for (x = 0; x < w; x++)
p[x] = link[p[x]];
delete[] link;
vector<vector<cv::Point>>contours;
vector<Vec4i>hierarchy;
uchar* gDataHead = new uchar[1024 * 1024 * 1]();
gData = gDataHead;
uint32_t cacheLen = 0;
ofstream f;
f.open(savePath, ios::out);
f << "G90" << endl;
f << "G0 X0 Y0 F" << speed << endl;
f << "M3 S0" << endl;
Mat tmpimg;
tmpimg.create(h, w, CV_8UC1);
tmpimg = Scalar(0);
uchar *tmpdata = (uchar*)tmpimg.data;
Mat dstImage = Mat::zeros(h, w, CV_8UC3);
unsigned int contours_size = 0;
double maxval;
for (int k = 1; k < t; k++)
{
for (int i = 0; i < h; i++)
{
for (int j = 0; j < w; j++)
{
if (label[j + i * w] == k)
{
tmpdata[j + i * w] = 255;
}
}
}
minMaxLoc(tmpimg, NULL, &maxval);
while (maxval != 0)
{
findContours(tmpimg, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
for (unsigned int i = 0; i < contours.size(); i++)
{
WriteGcodeString2(contours[i][0].x, contours[i][0].y, 0);
cacheLen++;
for (unsigned int j = 0; j < contours[i].size(); j++)
{
WriteGcodeString2(contours[i][j].x, contours[i][j].y, sMax);
cacheLen++;
if (cacheLen > 30000)
{
cacheLen = 0;
f << gDataHead;
f.flush();
memset(gDataHead, 0, 1024 * 1024 * 1);
gData = gDataHead;
}
}
WriteGcodeString2(contours[i][0].x, contours[i][0].y, sMax);
cacheLen++;
}
for (int index = 0; index >= 0; index = hierarchy[index][0])
{
drawContours(tmpimg, contours, index, Scalar(0), 1, 8, hierarchy);
}
minMaxLoc(tmpimg, NULL, &maxval);
}
}
f << gDataHead;
f << "M5" << endl;
f << "G0 X0 Y0 Z0" << endl;
f.flush();
f.close();
delete []gDataHead;
}
/*
* 快速模式转Gcode
*/
void ImageFastModeToGcode(Mat &srcImg, int linePerMillimetre, int engraveWidth, int engraveHeight, int sMax, int speed, string savePath)
{
Mat M1 = srcImg;
Mat M2;
resize(M1, M2, cv::Size(M1.cols * linePerMillimetre * engraveHeight / M1.rows, linePerMillimetre * engraveHeight), 0, 0, INTER_CUBIC);
quality = linePerMillimetre * 1.0;
M2 = M2 > 250;
flip(M2, M2, 0);
Mat labelImg;
Mat label;
label.create(M2.size(), CV_32SC1);
labelImg.create(M2.size(), CV_8UC1);
labelImg = Scalar(255);
labelImg.setTo(Scalar(0), M2);
bwLabel(labelImg.data, (int *)label.data, labelImg.rows, labelImg.cols, sMax, speed, savePath);
}
/*
* 切割转Gcode
*/
void ImageContoursToGCode(Mat &srcImg, int linePerMillimetre, int engraveWidth, int engraveHeight, int sMax, int speed, string savePath)
{
Mat M1 = srcImg;
Mat M2;
resize(M1, M2, cv::Size(M1.cols * linePerMillimetre * engraveHeight / M1.rows, linePerMillimetre * engraveHeight), 0, 0, INTER_CUBIC);
quality = linePerMillimetre * 1.0;
M2 = M2 < 250;
flip(M2, M2, 0);
uchar* gDataHead = new uchar[1024 * 1024 * 1]();
gData = gDataHead;
ofstream f;
f.open(savePath, ios::out);
f << "G90" << endl;
f << "G0 X0 Y0 F" << speed << endl;
f << "M3 S0" << endl;
uint32_t cacheLen = 0;
vector<vector<cv::Point>>contours;
vector<Vec4i>hierarchy;
findContours(M2, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
for (unsigned int i = 0; i < contours.size(); i++)
{
WriteGcodeString2(contours[i][0].x, contours[i][0].y, 0);
cacheLen++;
for (unsigned int j = 0; j < contours[i].size(); j++)
{
WriteGcodeString2(contours[i][j].x, contours[i][j].y, sMax);
cacheLen++;
if (cacheLen > 30000)
{
cacheLen = 0;
f << gDataHead;
f.flush();
memset(gDataHead, 0, 1024 * 1024 * 1);
gData = gDataHead;
}
}
WriteGcodeString2(contours[i][0].x, contours[i][0].y, sMax);
cacheLen++;
}
f << gDataHead;
f << "M5" << endl;
f << "G0 X0 Y0 Z0" << endl;
f.flush();
f.close();
delete[]gDataHead;
}
/*将图片转成GCode*/
+ (void)Image2GcodeFromImage:(UIImage *)image{
//UIImage 转 Mat
CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
CGFloat cols = image.size.width;
CGFloat rows = image.size.height;
cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels (color channels + alpha)
CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to data
cols, // Width of bitmap
rows, // Height of bitmap
8, // Bits per component
cvMat.step[0], // Bytes per row
colorSpace, // Colorspace
kCGImageAlphaNoneSkipLast |
kCGBitmapByteOrderDefault); // Bitmap info flags
CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage);
CGContextRelease(contextRef);
cvtColor(cvMat, cvMat, COLOR_BGR2RGB);
cv::cvtColor(cvMat, cvMat, CV_BGRA2GRAY);
cv::resize(cvMat, cvMat, cv::Size(), 0.5, 0.5);
//缓存路径 用来存储转换后的GCode文件
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
NSString *path_1 = [path stringByAppendingPathComponent:@"test.txt"];
string OUTPATH = string([path_1 UTF8String]); // NSString to string
//开始转换
ImageToGCodeOpenVC(cvMat, 12, cvMat.cols / 10, cvMat.rows / 10, 1000, 2500, false, true, OUTPATH);
}
@end
在需要将图片转换成GCode代码的地方,调用 Image2GcodeFromImage 方法就OK了!
有帮助的话,希望能给个赞!
网友评论