Upload files to "/"
This commit is contained in:
commit
b1c7ee5033
5 changed files with 257 additions and 0 deletions
27
GCODE_CHEATSHEET.txt
Normal file
27
GCODE_CHEATSHEET.txt
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
M00 – Program stop
|
||||||
|
M02 – End of program
|
||||||
|
M03 – Spindle ON – clockwise
|
||||||
|
M04 – Spindle ON – counterclockwise
|
||||||
|
M05 – Spindle stop
|
||||||
|
M06 – Tool change
|
||||||
|
M08 – Flood colant ON
|
||||||
|
M09 – Flood colant OFF
|
||||||
|
M30 – End of program
|
||||||
|
|
||||||
|
G00 - Move as fast as possible to location
|
||||||
|
G01 - Linear Interpolation
|
||||||
|
G02 - Circular Interpolation Clockwise
|
||||||
|
G03 - Circular Interpolation Counterclockwise
|
||||||
|
|
||||||
|
G17-19 - set plane to work on
|
||||||
|
G17 – XY plane
|
||||||
|
G18 – XZ plane
|
||||||
|
G19 – YZ plane
|
||||||
|
G20 - Set units to Inches
|
||||||
|
G21 - Set units to mm
|
||||||
|
|
||||||
|
G28 - Home
|
||||||
|
G29 - Bed Levelling
|
||||||
|
|
||||||
|
official docs:
|
||||||
|
https://machmotion.com/downloads/GCode/Mach3-GCode-Language-Reference.pdf
|
23
README.md
Normal file
23
README.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# CNSelfie
|
||||||
|
CNC machine that draws your selfies!
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
To run this you will need to install opencv-python and an altered version of svg_to_gcode, to do this make sure you dont have any other open-cv versions installed then run:
|
||||||
|
|
||||||
|
``pip install opencv-python``
|
||||||
|
and
|
||||||
|
``pip install svg-to-gcode``
|
||||||
|
|
||||||
|
Once you've installed svg-to-gcode, replace its file (in site-packages) with the zip file in this repo
|
||||||
|
|
||||||
|
This should also install numpy if you dont already have that
|
||||||
|
|
||||||
|
You might also find knowing a bit about G-Code will be helpful too, I didnt know
|
||||||
|
much about how it actually worked until now, I found [this](https://howtomechatronics.com/tutorials/g-code-explained-list-of-most-important-g-code-commands/) guide very helpful
|
||||||
|
|
||||||
|
## Todo
|
||||||
|
- [x] Allow user to take photos
|
||||||
|
- [x] Generate edges from photo
|
||||||
|
- [x] Convert edges to vector (probably using potrace)
|
||||||
|
- [x] Convert vector to G-Code (give [this](https://pypi.org/project/svg-to-gcode/) a look)
|
||||||
|
- [x] QoL changes to edge detection
|
170
main.py
Normal file
170
main.py
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
import cv2
|
||||||
|
import numpy
|
||||||
|
import time
|
||||||
|
import copy
|
||||||
|
import svg_to_gcode.compiler as Compiler
|
||||||
|
import svg_to_gcode.compiler.interfaces as Interfaces
|
||||||
|
import svg_to_gcode.svg_parser as Parser
|
||||||
|
|
||||||
|
EdgeMin = 150
|
||||||
|
EdgeMax = 200
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# code for function by ospider
|
||||||
|
# https://stackoverflow.com/questions/43108751/convert-contour-paths-to-svg-paths
|
||||||
|
def saveContoursAsSVG(contours, width, height, filename):
|
||||||
|
with open(filename, "w+") as f:
|
||||||
|
f.write(f'<svg width="{width}" height="{height}" xmlns="http://www.w3.org/2000/svg">')
|
||||||
|
|
||||||
|
for c in contours:
|
||||||
|
f.write('<path d="M')
|
||||||
|
for i in range(len(c)):
|
||||||
|
x, y = c[i][0]
|
||||||
|
f.write(f"{x} {y} ")
|
||||||
|
f.write('" style="stroke:pink"/>')
|
||||||
|
f.write("</svg>")
|
||||||
|
|
||||||
|
def contoursToSVG(contours, width, height):
|
||||||
|
result = ""
|
||||||
|
result += '<svg width="' + str(width) + '" height="' + str(height) \
|
||||||
|
+ '" xmlns="http://www.w3.org/2000/svg">'
|
||||||
|
|
||||||
|
for c in contours:
|
||||||
|
result += '<path d="M'
|
||||||
|
for i in range(len(c)):
|
||||||
|
x, y = c[i][0]
|
||||||
|
result += str(x) + " " + str(y) + " "
|
||||||
|
result += '" style="stroke:pink"/>'
|
||||||
|
result += "</svg>"
|
||||||
|
return result
|
||||||
|
|
||||||
|
def contoursToGCode(contours, width, height, filename):
|
||||||
|
compiler = Compiler.Compiler(Interfaces.Gcode, movement_speed=2000, cutting_speed=2000, pass_depth=1)
|
||||||
|
curves = Parser.parse_string(contoursToSVG(contours, width, height))
|
||||||
|
compiler.append_curves(curves)
|
||||||
|
compiler.compile_to_file(filename)
|
||||||
|
print("success!")
|
||||||
|
|
||||||
|
def scaleContours(contours, scale):
|
||||||
|
result = []
|
||||||
|
for contour in contours:
|
||||||
|
resultingContour = []
|
||||||
|
for point in contour:
|
||||||
|
x = int(float(point[0][0])*scale)
|
||||||
|
y = int(float(point[0][1])*scale)
|
||||||
|
resultingPoint = [[x, y]]
|
||||||
|
resultingContour.append(resultingPoint)
|
||||||
|
result.append(resultingContour)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def getMin(a, b):
|
||||||
|
if a <= -1:
|
||||||
|
return b
|
||||||
|
elif b <= -1:
|
||||||
|
return a
|
||||||
|
elif a < b:
|
||||||
|
return a
|
||||||
|
else:
|
||||||
|
return b
|
||||||
|
|
||||||
|
def getMax(a, b):
|
||||||
|
if a > b:
|
||||||
|
return a
|
||||||
|
else:
|
||||||
|
return b
|
||||||
|
|
||||||
|
def calculateDrift(contours, frame):
|
||||||
|
xDrift = -1
|
||||||
|
yDrift = -1
|
||||||
|
|
||||||
|
for contour in contours:
|
||||||
|
for point in contour:
|
||||||
|
xDrift = getMin(point[0][0], xDrift)
|
||||||
|
yDrift = getMax(point[0][1], yDrift)
|
||||||
|
|
||||||
|
yDrift -= frame.shape[1]
|
||||||
|
|
||||||
|
return xDrift, yDrift
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def correctContours(contours, frame):
|
||||||
|
result = []
|
||||||
|
|
||||||
|
x, y = calculateDrift(contours, frame)
|
||||||
|
|
||||||
|
for contour in contours:
|
||||||
|
resultingContour = []
|
||||||
|
#print(contour)
|
||||||
|
for point in contour:
|
||||||
|
#print(point)
|
||||||
|
resultingX = point[0][0]-x
|
||||||
|
resultingY = point[0][1]-y
|
||||||
|
resultingPoint = [[resultingX, resultingY]]
|
||||||
|
resultingContour.append(resultingPoint)
|
||||||
|
result.append(resultingContour)
|
||||||
|
#print(result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# displays a single frame ready to print
|
||||||
|
def Capture(frame):
|
||||||
|
windowName = "Result"
|
||||||
|
while True:
|
||||||
|
textFrame = copy.deepcopy(frame) # create copy of frame to add text to and display
|
||||||
|
cv2.putText(textFrame, "W to take new photo, E to print", (0, 450), fontFace=cv2.FONT_HERSHEY_PLAIN, fontScale=1, color=(255, 255, 255), thickness=2)
|
||||||
|
cv2.imshow(windowName, textFrame)
|
||||||
|
input = cv2.waitKey(1)
|
||||||
|
if input == ord('w'):
|
||||||
|
cv2.destroyWindow(windowName)
|
||||||
|
break
|
||||||
|
elif input == ord('e'):
|
||||||
|
# Do I really have to save then rewrite the file for this...
|
||||||
|
contours, hierachy = cv2.findContours(frame, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
|
||||||
|
contours = scaleContours(contours, 0.25)
|
||||||
|
contours = correctContours(contours, frame)
|
||||||
|
contoursToGCode(contours, frame.shape[0], frame.shape[1], "test.gcode")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
cap = cv2.VideoCapture(0)
|
||||||
|
liveCanny = False
|
||||||
|
if not cap.isOpened:
|
||||||
|
raise RuntimeError("Failed to instantiate VideoCapture object :(")
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# take frame from camera
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
print("##WARNING## - VideoCapture object failed to capture frame")
|
||||||
|
|
||||||
|
cannyFrame = cv2.Canny(frame, EdgeMin, EdgeMax)
|
||||||
|
|
||||||
|
# input
|
||||||
|
input = cv2.waitKey(1)
|
||||||
|
if input == ord(' '):
|
||||||
|
# we need to apply canny first
|
||||||
|
Capture(cannyFrame)
|
||||||
|
elif input == ord('r'):
|
||||||
|
liveCanny = not liveCanny
|
||||||
|
elif input == ord('q'):
|
||||||
|
break
|
||||||
|
|
||||||
|
# output to screen, optionally applies edge detection
|
||||||
|
if liveCanny:
|
||||||
|
frame = cannyFrame
|
||||||
|
cv2.putText(frame, "Space to take photo | R to show edges | Q to quit", (0, 450), fontFace=cv2.FONT_HERSHEY_PLAIN, fontScale=1, color=(255, 255, 255), thickness=2)
|
||||||
|
cv2.imshow("Camera", frame)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cap.release()
|
||||||
|
cv2.destroyAllWindows()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
37
pngToSvgTest.py
Normal file
37
pngToSvgTest.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import cv2
|
||||||
|
import copy
|
||||||
|
|
||||||
|
# code for function by ospider
|
||||||
|
# https://stackoverflow.com/questions/43108751/convert-contour-paths-to-svg-paths
|
||||||
|
def saveContoursAsSVG(contours, width, height, filename):
|
||||||
|
with open(filename, "w+") as f:
|
||||||
|
f.write(f'<svg width="{width}" height="{height}" xmlns="http://www.w3.org/2000/svg">')
|
||||||
|
|
||||||
|
for c in contours:
|
||||||
|
f.write('<path d="M')
|
||||||
|
for i in range(len(c)):
|
||||||
|
x, y = c[i][0]
|
||||||
|
f.write(f"{x} {y} ")
|
||||||
|
f.write('" style="stroke:pink"/>')
|
||||||
|
f.write("</svg>")
|
||||||
|
|
||||||
|
|
||||||
|
image = cv2.imread("test.png")
|
||||||
|
image2 = copy.deepcopy(image) # image to overwrite with contours
|
||||||
|
|
||||||
|
# do contour detection WOW
|
||||||
|
image = cv2.Canny(image, 150, 200)
|
||||||
|
contours, hierachy = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
|
||||||
|
|
||||||
|
|
||||||
|
cv2.drawContours(image2, contours, -1, (255,255,255), 3)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
cv2.imshow("FUCKSKFKSDG", image2)
|
||||||
|
key = cv2.waitKey(1)
|
||||||
|
if key == ord('q'):
|
||||||
|
break
|
||||||
|
elif key == ord('w'):
|
||||||
|
saveContoursAsSVG(contours, image2, "test.svg") ## this is nasty soz
|
||||||
|
|
||||||
|
cv2.destroyAllWindows()
|
BIN
svg_to_gcode.zip
Normal file
BIN
svg_to_gcode.zip
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue