├── Image ├── IMG_3022.JPG ├── IMG_3023.JPG ├── IMG_3026 .JPG ├── 位图模式.PNG ├── 轮廓模式.PNG └── 轮廓连续雕刻.PNG ├── README.md ├── main.py └── mainwindows.py /Image/IMG_3022.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yizheneng/ImageToGcodeTools/4ff6765f73605184ae5420ba76fe299b8111dc83/Image/IMG_3022.JPG -------------------------------------------------------------------------------- /Image/IMG_3023.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yizheneng/ImageToGcodeTools/4ff6765f73605184ae5420ba76fe299b8111dc83/Image/IMG_3023.JPG -------------------------------------------------------------------------------- /Image/IMG_3026 .JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yizheneng/ImageToGcodeTools/4ff6765f73605184ae5420ba76fe299b8111dc83/Image/IMG_3026 .JPG -------------------------------------------------------------------------------- /Image/位图模式.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yizheneng/ImageToGcodeTools/4ff6765f73605184ae5420ba76fe299b8111dc83/Image/位图模式.PNG -------------------------------------------------------------------------------- /Image/轮廓模式.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yizheneng/ImageToGcodeTools/4ff6765f73605184ae5420ba76fe299b8111dc83/Image/轮廓模式.PNG -------------------------------------------------------------------------------- /Image/轮廓连续雕刻.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yizheneng/ImageToGcodeTools/4ff6765f73605184ae5420ba76fe299b8111dc83/Image/轮廓连续雕刻.PNG -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 位图转微型激光雕刻机G代码程序 # 2 | 3 | # 1、预计实现功能 4 | ## 1)位图逐点雕刻 5 | ## 2)雕刻位图的轮廓 6 | # 2、支持的G代码指令 7 | ## 1)G0 快速移动指令 8 | ## 2)G4 延时指令 9 | ## 3)M3 开启激光指令 10 | ## 4)M5 关闭激光指令 11 | # 3、开发或运行环境 12 | python + PyQt4 + opencv 13 | # 4、特色功能 14 | ## 1)位图雕刻采用蛇形路线,节约雕刻时间 15 | ## 2)支持轮廓雕刻模式,可以只雕刻轮廓 16 | 17 | 18 | # License 19 | [![996.icu](https://img.shields.io/badge/link-996.icu-red.svg)](https://996.icu) 20 | [![LICENSE](https://img.shields.io/badge/license-Anti%20996-blue.svg)](https://github.com/996icu/996.ICU/blob/master/LICENSE) 21 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui 2 | from mainwindows import MainWindow 3 | 4 | if __name__ == "__main__": 5 | app = QtGui.QApplication([]) 6 | m = MainWindow() 7 | m.show() 8 | app.exec_() -------------------------------------------------------------------------------- /mainwindows.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | from PyQt4.QtGui import QMainWindow, QSpinBox, QPushButton, QPixmap,\ 3 | qGray, QCheckBox 4 | 5 | from PyQt4.Qt import QWidget, QVBoxLayout, QDoubleSpinBox, QHBoxLayout, QFileDialog, QMessageBox,\ 6 | QImage, qRgb, QLabel 7 | 8 | import cv2 as cv 9 | import numpy as np 10 | 11 | class MainWindow(QWidget): 12 | def __init__(self): 13 | QMainWindow.__init__(self) 14 | self.resize(500, 300) 15 | 16 | self.mainLayout = QHBoxLayout() 17 | self.chooseLayout = QHBoxLayout() 18 | self.continuousLayout = QHBoxLayout() 19 | self.layout = QVBoxLayout() 20 | self.pixLayout = QHBoxLayout() 21 | self.thresholdLayout = QHBoxLayout() 22 | self.timeLayout = QHBoxLayout() 23 | self.contoursLayout = QHBoxLayout() 24 | self.setLayout(self.mainLayout) 25 | self.setWindowTitle("Image To Gcode V1.0 ----- build By yizheneng kangbo0303@163.com") 26 | 27 | self.imageLabel = QLabel("image") 28 | 29 | self.mainLayout.addWidget(self.imageLabel) 30 | self.mainLayout.addLayout(self.layout) 31 | self.mainLayout.setStretchFactor(self.layout, 1) 32 | self.mainLayout.setStretchFactor(self.imageLabel, 3) 33 | 34 | self.pixLengthLabel = QLabel(u"像素大小(mm):") 35 | self.pixDoubleSpinBox = QDoubleSpinBox() 36 | self.pixDoubleSpinBox.setValue(1) 37 | self.pixDoubleSpinBox.setDecimals(6) 38 | self.pixLayout.addWidget(self.pixLengthLabel) 39 | self.pixLayout.addWidget(self.pixDoubleSpinBox) 40 | 41 | self.thresholdLabel = QLabel(u"阈值:") 42 | self.thresholdSpinBox = QSpinBox() 43 | self.thresholdSpinBox.valueChanged.connect(self.ThresholdValChange) 44 | self.thresholdSpinBox.setMaximum(255) 45 | self.thresholdSpinBox.setValue(120) 46 | self.thresholdLayout.addWidget(self.thresholdLabel) 47 | self.thresholdLayout.addWidget(self.thresholdSpinBox) 48 | 49 | self.timeLabel = QLabel(u"灼烧时间:") 50 | self.timeDoubleSpinBox = QDoubleSpinBox() 51 | self.timeDoubleSpinBox.setValue(0.3) 52 | self.timeLayout.addWidget(self.timeLabel) 53 | self.timeLayout.addWidget(self.timeDoubleSpinBox) 54 | 55 | self.chooseLabel = QLabel(u"只雕刻轮廓:") 56 | self.chooseBox = QCheckBox() 57 | self.chooseLayout.addWidget(self.chooseLabel) 58 | self.chooseLayout.addWidget(self.chooseBox) 59 | self.chooseBox.stateChanged.connect(self.ChooseValChanged) 60 | 61 | self.continuousLabel = QLabel(u"连续雕刻:") 62 | self.continuousBox = QCheckBox() 63 | self.continuousBox.setEnabled(False) 64 | self.continuousBox.stateChanged.connect(self.ChooseValChanged) 65 | self.continuousLayout.addWidget(self.continuousLabel) 66 | self.continuousLayout.addWidget(self.continuousBox) 67 | 68 | self.contoursWidthLabel = QLabel(u"边框宽度") 69 | self.ContoursWidthSpinBox = QSpinBox() 70 | self.ContoursWidthSpinBox.setEnabled(False) 71 | self.ContoursWidthSpinBox.setValue(1) 72 | self.contoursLayout.addWidget(self.contoursWidthLabel) 73 | self.contoursLayout.addWidget(self.ContoursWidthSpinBox) 74 | 75 | 76 | self.loadImageButton = QPushButton(u"加载图片") 77 | self.loadImageButton.clicked.connect(self.LoadImageButtonClicked) 78 | self.previewButton = QPushButton(u"预览") 79 | self.previewButton.clicked.connect(self.ThresholdValChange) 80 | self.makeCodeButton = QPushButton(u"生成G代码") 81 | self.makeCodeButton.clicked.connect(self.MakeGcode) 82 | 83 | 84 | self.layout.addLayout(self.pixLayout) 85 | self.layout.addLayout(self.thresholdLayout) 86 | self.layout.addLayout(self.timeLayout) 87 | self.layout.addLayout(self.chooseLayout) 88 | self.layout.addLayout(self.continuousLayout) 89 | self.layout.addLayout(self.contoursLayout) 90 | self.layout.addWidget(self.loadImageButton) 91 | self.layout.addWidget(self.previewButton) 92 | self.layout.addWidget(self.makeCodeButton) 93 | 94 | def LoadImageButtonClicked(self): 95 | self.filePath = QFileDialog.getOpenFileName(self, u"选择图片文件", "", "Images (*.bmp)") 96 | if self.filePath == "": 97 | QMessageBox.warning(self, u"发生错误", u"没有选择可以识别的文件!!") 98 | return 99 | 100 | self.srcImage = QImage(self.filePath) 101 | self.grayImage = QImage(self.srcImage.size(), QImage.Format_Indexed8) 102 | 103 | for i in range(256): 104 | self.grayImage.setColor(i, qRgb(i, i, i)) 105 | 106 | for i in range(self.srcImage.width()): 107 | for j in range(self.srcImage.height()): 108 | temp = qGray(self.srcImage.pixel(i, j)) 109 | self.grayImage.setPixel(i, j, temp) 110 | 111 | self.srcImage = QImage(self.grayImage) 112 | self.resultImage = QImage(self.grayImage) 113 | self.imageLabel.setPixmap(QPixmap(self.srcImage)) 114 | 115 | def ChooseValChanged(self): 116 | self.continuousBox.setEnabled(self.chooseBox.isChecked()) 117 | self.ContoursWidthSpinBox.setEnabled((self.chooseBox.isChecked()) and (not self.continuousBox.isChecked())) 118 | 119 | def ThresholdValChange(self): 120 | for i in range(self.srcImage.width()): 121 | for j in range(self.srcImage.height()): 122 | temp = self.srcImage.pixelIndex(i, j) 123 | if(temp >= self.thresholdSpinBox.value()): 124 | self.grayImage.setPixel(i, j, 255) 125 | else: 126 | self.grayImage.setPixel(i, j, 0) 127 | self.resultImage = QImage(self.grayImage) 128 | #如果选中了只雕刻轮廓 129 | if self.chooseBox.isChecked(): 130 | img = np.zeros((self.grayImage.height(), self.grayImage.width(), 1), np.uint8) 131 | for i in range(self.grayImage.width()): 132 | for j in range(self.grayImage.height()): 133 | img[j, i] = self.grayImage.pixelIndex(i, j) 134 | #提取轮廓 135 | contours = cv.findContours(img, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE) 136 | img = np.zeros((self.grayImage.height(), self.grayImage.width(), 1), np.uint8) 137 | cv.drawContours(img, contours[1][:-1], -1, (255, 255, 255), self.ContoursWidthSpinBox.value()) 138 | self.contours = contours[1][:-1] 139 | #转换轮廓到显示界面 140 | for i in range(self.resultImage.width()): 141 | for j in range(self.resultImage.height()): 142 | if img[j, i] == 0: 143 | self.resultImage.setPixel(i, j, 255) 144 | else: 145 | self.resultImage.setPixel(i, j, 0) 146 | 147 | self.imageLabel.setPixmap(QPixmap(self.resultImage)) 148 | 149 | def MakeGcode(self): 150 | path = QFileDialog.getSaveFileName(self, u"选择保存路径", "", " (*.nc)") 151 | if path == "": 152 | QMessageBox.warning(self, u"发生错误", u"路径错误!!") 153 | return 154 | 155 | f = open(path, 'w') 156 | f.write("M5\n") 157 | 158 | if self.continuousBox.isChecked() and self.chooseBox.isChecked(): 159 | for contour in self.contours: 160 | f.write("G0 X%f Y%f\n" % ((contour[0][0][0] * self.pixDoubleSpinBox.value()), (contour[0][0][1] * self.pixDoubleSpinBox.value()))) 161 | f.write("M3\n") 162 | for con in contour: 163 | f.write("G0 X%f Y%f\n" % ((con[0][0] * self.pixDoubleSpinBox.value()), (con[0][1] * self.pixDoubleSpinBox.value()))) 164 | 165 | f.write("G0 X%f Y%f\n" % ((contour[0][0][0] * self.pixDoubleSpinBox.value()), (contour[0][0][1] * self.pixDoubleSpinBox.value()))) 166 | f.write("M5\n") 167 | else: 168 | for i in range(self.resultImage.width()): 169 | flag = False 170 | #检测这一行是否有点 171 | for j in range(self.resultImage.height()): 172 | if self.resultImage.pixelIndex(i, j) < 128: 173 | flag = True 174 | break 175 | #如果这一行都没有点则跳过这一行 176 | if flag: 177 | f.write("G0 Y%f\n"% (i * self.pixDoubleSpinBox.value())) 178 | else: 179 | continue 180 | 181 | if (i % 2) > 0: 182 | for j in range(self.resultImage.height()): 183 | if self.resultImage.pixelIndex(i, j) < 128: 184 | f.write("G0 X%f\n" % (j * self.pixDoubleSpinBox.value())) 185 | f.write("M3\n") 186 | f.write("G4 P%f\n" % self.timeDoubleSpinBox.value()) 187 | f.write("M5\n") 188 | else: 189 | for j in range(self.resultImage.height())[::-1]: 190 | if self.resultImage.pixelIndex(i, j) < 128: 191 | f.write("G0 X%f\n" % (j * self.pixDoubleSpinBox.value())) 192 | f.write("M3\n") 193 | f.write("G4 P%f\n" % self.timeDoubleSpinBox.value()) 194 | f.write("M5\n") 195 | 196 | f.write("M5\n") 197 | f.write("G0 X0 Y0\n") 198 | f.close() 199 | QMessageBox.information(self, u"成功", u"生成G代码文件成功!!") --------------------------------------------------------------------------------