Advertisement
j0h

camera2svg

j0h
Feb 18th, 2023
974
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.50 KB | None | 0 0
  1. #!/home/m/anaconda3/bin/python3
  2. #https://hackaday.io/project/179946-image-to-svg-and-g-code-converter
  3. import pkg_resources
  4. import subprocess
  5. import sys
  6. import os
  7.  
  8. REQUIRED = {
  9.   'tk', 'opencv-python', 'numpy', 'pathlib',
  10.   'Pillow'
  11. }
  12.  
  13. installed = {pkg.key for pkg in pkg_resources.working_set}
  14. missing = REQUIRED - installed
  15.  
  16. # Automatically installing missing packages
  17.  
  18. # Comment these out if want to install them manually
  19.  
  20. if missing:
  21.     python = sys.executable
  22.     subprocess.check_call([python, '-m', 'pip', 'install', *missing], stdout=subprocess.DEVNULL)
  23.  
  24.  
  25. from tkinter import *    # from tkinter import Tk for Python 3.x
  26. from tkinter.filedialog import askopenfilename
  27. from tkinter import messagebox as MB
  28. import cv2
  29. from pathlib import Path
  30. import math
  31. import numpy as np
  32. from PIL import Image, ImageTk
  33. import image_process as IP
  34. from tkinter import ttk
  35. from tkinter import scrolledtext
  36.  
  37.  
  38. #------------- Main window creation ----------------
  39.  
  40. root = Tk()
  41. root.title('SVG From Camera')
  42.  
  43. tabControl = ttk.Notebook(root)
  44. tab1 = ttk.Frame(tabControl)
  45. tabControl.add(tab1, text="Image upload")
  46. tabControl.pack(expand=1, fill="both")
  47.  
  48. root.geometry('1020x900')
  49.  
  50. #-------------Contour detection variables ---------------
  51.  
  52. image_path = StringVar()
  53. image_name = StringVar()
  54. ##gcode_var = StringVar()
  55. thresh_min = IntVar()
  56. thresh_min.set(60)
  57. thresh_max = IntVar()
  58. thresh_max.set(255)
  59. inv_contour = BooleanVar()
  60. choosen_blur = StringVar()
  61. choices = ['Gaussian Blur', 'Simple Blur', 'Median Blur', 'Bilateral Filter', '2D Filter', 'Laplacian', 'No Blur']
  62. choosen_blur.set(choices[5])
  63. max_image_area = IntVar()
  64. min_image_area = IntVar()
  65. conture_threshold = BooleanVar()
  66. min_contour_area = IntVar()
  67. max_contour_area = IntVar()
  68.  
  69. vertical_mirror = BooleanVar()
  70. vertical_mirror.set(False)
  71. horizontal_mirror = BooleanVar()
  72. horizontal_mirror.set(False)
  73.  
  74. #------------- Image variables --------------------
  75.  
  76. preparedImage = None
  77. blurred_process = None
  78. blurred_show = None
  79. contourCanvas = None
  80. tkImageOri = None
  81. tkImageGray = None
  82. tkImageBlurred = None
  83. tkImageContour = None
  84. tkImageContourZoom = None
  85. final_contours = None
  86. isFirstRun=True
  87. cv2Image = None
  88. filteredContourArray = None
  89.  
  90.  
  91.  
  92. # ---------------- Functions -----------------------
  93.  
  94. # Start when clicking Upload image or New Image buttons, let's you choose a file and reads it
  95. def uploadImage():
  96.     #uploadImage
  97.     cam = cv2.VideoCapture(0)  
  98.     s, img = cam.read()
  99.     if s:
  100.         cv2.imwrite("filename.jpg",img)
  101.     filepath=("filename.jpg")
  102.     path = Path(filepath)
  103.     ##path = Path(filepath)
  104.     image_name.set(path.stem)
  105.  
  106.    
  107.     # Set global variable: Filename
  108.     image_path.set(filepath)
  109.  
  110.     print(image_name.get())
  111.  
  112.     # Prepare image for edge detection
  113.  
  114.     if filepath == "":
  115.         print("No image selected")
  116.         return None
  117.  
  118.    
  119.     # Refresh label widgets
  120.     setImages()
  121.    
  122. # Creates the different images types from the uploaded image
  123. def createContoures(isInv,thresh_min):
  124.     global tkImageContour
  125.     global final_contours
  126.  
  127.     if blurred_process is None:
  128.         return None
  129.    
  130.     #global thres_min
  131.     # Big image find contours  
  132.     thresh_min = thres_min_scale.get()
  133.     contours_big = IP.detectContours(blurred_process, isInv,thresh_min)
  134.  
  135.     if contours_big != None:
  136.         gcode_gen_button.configure(state="active")
  137.         final_contours = contours_big
  138.  
  139.     # Small image find contours and draw
  140.     #contours_show = IP.detectContours(blurred_process)
  141.     contourCanvas = np.zeros(contourCanvas.shape, np.uint8)
  142.     contourImage, approx = IP.drawContoursOnCanvas(contourCanvas, contours_big)
  143.  
  144.     # Convert OpenCV canvas image to tKinter image
  145.     tkim = Image.fromarray(resizedCanvas)
  146.     imgtk_contour = ImageTk.PhotoImage(image=tkim)
  147.     tkImageContour = imgtk_contour
  148.  
  149. # Sets the global image variable to the previously created images, and show them on the UI
  150. def setImages():
  151.  
  152.     global isFirstRun
  153.     try:
  154.         tkimage_ori, tkimage_gray, tkimage_blurred, tkimage_contour, tkimage_contour_zoom, max_area, min_area, cv2image, filteredContours = IP.createPreviewImages(image_path.get(), thresh_min.get(), thresh_max.get(), inv_contour.get(), choosen_blur.get(), min_contour_area.get(), max_contour_area.get(), conture_threshold.get(), horizontal_mirror.get(), vertical_mirror.get())
  155.     except Exception as e:
  156.         MB.showerror(title="Error", message="Image format is not supported")
  157.         print(e)
  158.         return
  159.        
  160.     im_upload_button.place_forget()
  161.     max_image_area.set(round(max_area))
  162.     min_image_area.set(round(min_area))
  163.  
  164.     area_thresh_min_scale.configure(from_=min_area,to=max_area, variable=min_contour_area)
  165.     area_thresh_max_scale.configure(from_=min_area,to=max_area, variable=max_contour_area)
  166.  
  167.     if isFirstRun:
  168.         area_thresh_max_scale.set(max_image_area.get())
  169.         isFirstRun = False
  170.  
  171.     area_thresh_frame.grid(row=4, column=0)
  172.  
  173.     global contourCanvas
  174.     contourCanvas = tkimage_contour
  175.  
  176.     global tkImageOri
  177.     tkImageOri = tkimage_ori
  178.  
  179.     global tkImageGray
  180.     tkImageGray = tkimage_gray
  181.  
  182.     global tkImageBlurred
  183.     tkImageBlurred = tkimage_blurred
  184.  
  185.     global tkImageContour
  186.     tkImageContour = tkimage_contour
  187.  
  188.     global tkImageContourZoom
  189.     tkImageContourZoom = tkimage_contour_zoom
  190.  
  191.     global cv2Image
  192.     cv2Image = cv2image
  193.  
  194.     global filteredContourArray
  195.     filteredContourArray = filteredContours
  196.  
  197.     # Update image labels with global variables
  198.    
  199.     im_ori_show_label.configure(image=tkImageOri)
  200.    
  201.     im_gray_show_label.configure(image=tkImageGray)
  202.    
  203.     im_blurred_show_label.configure(image=tkImageBlurred)
  204.    
  205.     im_contour_show_label.configure(image=tkImageContour)
  206.  
  207.     im_zoom_label.configure(image=tkImageContourZoom)
  208.  
  209.     all_contour_settings_frame.grid(row=0, column=1, padx=10)
  210.  
  211. # When 'Contour area filter' is off, this hides the corresponding sliders
  212. def hideContourThreshold():
  213.     if conture_threshold.get():
  214.         area_thresh_frame.configure(height=140)
  215.         area_thresh_min_scale.grid(row=1, column=0)
  216.         area_thresh_max_scale.grid(row=2, column=0)
  217.        
  218.     else:
  219.        
  220.         area_thresh_min_scale.grid_forget()
  221.         area_thresh_max_scale.grid_forget()
  222.         area_thresh_frame.configure(height=40)
  223.  
  224. # When clicking on any of the images it zooms in the contour (svg type) image
  225. def zoomImage(imageName):
  226.    
  227.     im_ori_show_label.grid_forget()
  228.     im_gray_show_label.grid_forget()
  229.     im_blurred_show_label.grid_forget()
  230.     im_contour_show_label.grid_forget()
  231.  
  232.     im_zoom_label.grid(row=0, column = 0, sticky=W)
  233.  
  234. # When clicking on the zoomed image, this zooms it out
  235. def closeZoomImage():
  236.    
  237.     im_zoom_label.grid_forget()
  238.     im_ori_show_label.grid(row=0, column = 0, sticky=W)
  239.     im_gray_show_label.grid(row=0, column = 1, sticky=W)
  240.     im_blurred_show_label.grid(row=1, column =0, sticky=W)
  241.     im_contour_show_label.grid(row=1, column = 1, sticky=W)
  242.  
  243. # Starts the SVG creating process
  244. def getSVG():
  245.     success = IP.createSVG(image_name.get())
  246.     if success:
  247.         MB.showinfo(title="Success", message="SVG has been created and saved in the 'output' directory")
  248.     else:
  249.         MB.showerror(title="Error", message="An error occured during SVG creation")
  250.  
  251.  
  252.  
  253. #---------------------------- Image upload tab ------------------------------
  254.  
  255. # Left column on the tab, holds the images
  256.  
  257. image_frame = Frame(tab1, width=660, height=900, relief="flat")
  258. image_frame.grid(row=0, column=0)
  259. image_frame.rowconfigure(0, weight=1)
  260. image_frame.columnconfigure(0, weight=1)
  261. image_frame.grid_propagate(0)
  262.  
  263. # This is kinda the same as the previous one
  264. image_preview_frame = Frame(image_frame, width=660, height=900, relief="flat")
  265. image_preview_frame.grid(row=0, column=0)
  266.  
  267.  
  268.     # Original image
  269. im_ori_show_label = Label(image_preview_frame, image = None, pady = 20)
  270. im_ori_show_label.grid(row=0, column = 0, sticky=W)
  271. im_ori_show_label.bind("<Button-1>", lambda e: zoomImage("originalImage"))
  272.  
  273.     # Gray Image
  274. im_gray_show_label = Label(image_preview_frame, image = None, pady = 20)
  275. im_gray_show_label.grid(row=0, column = 1, sticky=W)
  276. im_gray_show_label.bind("<Button-1>", lambda e: zoomImage("grayImage"))
  277.  
  278.     # Blurred Image
  279. im_blurred_show_label = Label(image_preview_frame, image = None, pady = 20)
  280. im_blurred_show_label.grid(row=1, column =0, sticky=W)
  281. im_blurred_show_label.bind("<Button-1>", lambda e: zoomImage("blurredImage"))
  282.  
  283.     # Contour image
  284. im_contour_show_label = Label(image_preview_frame, image = None, pady = 20)
  285. im_contour_show_label.grid(row=1, column = 1, sticky=W)
  286. im_contour_show_label.bind("<Button-1>", lambda e: zoomImage("contourImage"))
  287.  
  288.     # Zoomed image, it's hidden by default
  289. im_zoom_label = Label(image_frame, image = tkImageContourZoom, pady = 20, width=660, height=800)
  290. im_zoom_label.bind("<Button-1>", lambda e: closeZoomImage())
  291.    
  292.  
  293.     # Image upload button, it hides after an image is uploaded
  294. im_upload_button = Button(tab1, text="Upload image", command=uploadImage)
  295. im_upload_button.place(relx=0.5, rely=0.5,anchor=CENTER)
  296.  
  297.  
  298. # Contour detection parameter sliders and checkboxes (second column on the tab)
  299.  
  300.  
  301.     # The frame holding all the paramaters
  302. all_contour_settings_frame = Frame(tab1, width=340, height=800)
  303. all_contour_settings_frame.grid_propagate(0)
  304. all_contour_settings_frame.columnconfigure(0, weight=1)
  305.  
  306.  
  307. # --------------- New image and refresh button frame ------------------------------
  308. newimage_frame = Frame(all_contour_settings_frame, width=320, height=40, highlightbackground="black", highlightthickness=1, pady=5)
  309. newimage_frame.grid(column=0, row=0)
  310. newimage_frame.grid_propagate(0)
  311. #Lovejoy
  312. new_image_button = Button(newimage_frame,text="New image", command=uploadImage)
  313. new_image_button.grid(column=0, row=0, padx=40)
  314.  
  315. recontour_button = Button(newimage_frame,text="Recontour image", command=setImages)
  316. recontour_button.grid(column=1, row=0,padx=40)
  317.  
  318.  
  319. # ----------- Spacing Frame ----------
  320.  
  321. spacing_frame = Frame(all_contour_settings_frame, width=320, height=20)
  322. spacing_frame.grid(column=0, row=1)
  323.  
  324. #------------  Detection settings frame ------------------
  325. detection_settings_frame = Frame(all_contour_settings_frame, width=320, height=370, highlightthickness=1, highlightbackground="black")
  326. detection_settings_frame.grid(row=2, column=0)
  327. detection_settings_frame.grid_propagate(0)
  328. detection_settings_frame.columnconfigure(0, weight=1)
  329.  
  330.     # Title of the group
  331. detection_settings_label = Label(detection_settings_frame, text="Contour detection parameters")
  332. detection_settings_label.grid(row=0, column=0, pady=10)
  333.    
  334.     # Detection minimum frame # row 0,
  335. thresh_min_frame = Frame(detection_settings_frame, width=340, height=70)
  336. thresh_min_frame.grid(row=1, column=0,padx=0, pady=10)
  337. thresh_min_frame.grid_propagate(0)
  338. thresh_min_frame.columnconfigure(0, weight=1)
  339.  
  340. thresh_min_label = Label(thresh_min_frame, text="Threshold minimum value")
  341.    
  342. thres_min_scale = Scale(thresh_min_frame, from_=1, to=254, orient=HORIZONTAL,length=300, variable=thresh_min, label="Detection minimum")
  343. thres_min_scale.grid(row=1, column=0,padx=5, pady=0)
  344.  
  345.     #Detection maximum frame # row 1
  346. thresh_max_frame = Frame(detection_settings_frame, width=340, height=70)
  347. thresh_max_frame.grid(row=2, column=0, padx=0, pady=10)
  348. thresh_max_frame.columnconfigure(0, weight=1)
  349.  
  350. thresh_max_label = Label(thresh_max_frame, text="Threshold maximum")
  351.  
  352. thres_max_scale = Scale(thresh_max_frame, from_=1, to=254, orient=HORIZONTAL,length=300, variable=thresh_max, label="Detection maximum")
  353. thres_max_scale.grid(row=1, column=0,padx=5)
  354.  
  355.     # Inverse contour checkkox # row 2
  356. inv_contour_checkbox = Checkbutton(detection_settings_frame, text="Inverse binary contours detection", variable=inv_contour, onvalue=True, offvalue=False)
  357. inv_contour_checkbox.grid(row=3, column=0, pady=10)
  358.  
  359.     # Blur mode dropdrown # row 3
  360. blur_mode_frame = Frame(detection_settings_frame, width=340, height=50)
  361. blur_mode_frame.grid(row=4, column=0, padx=0, pady=10)
  362. blur_mode_frame.columnconfigure(0, weight=1)
  363.  
  364. blur_mode_label = Label(blur_mode_frame, text="Blur type")
  365. blur_mode_label.grid(row=0, column=0,padx=30)
  366.  
  367. blur_mode_dropdown = OptionMenu(blur_mode_frame, choosen_blur, *choices)
  368. blur_mode_dropdown.grid(row=1, column=0, pady=0)
  369.  
  370. #----------- Spacing frame --------------
  371.  
  372. spacing_frame_2 = Frame(all_contour_settings_frame, width=320, height=20)
  373. spacing_frame_2.grid(column=0, row=3)
  374.  
  375. #----------------------------------------
  376.  
  377.  
  378.  
  379. #----------- Contour area filters frame ----------------
  380.  
  381. area_thresh_frame = Frame(all_contour_settings_frame, width=320, height=40, highlightbackground="black", highlightthickness=1, pady=5, padx=5)
  382. area_thresh_frame.columnconfigure(0, weight=1)
  383. area_thresh_frame.grid_propagate(0)
  384.  
  385.     # Contour area filter ON/OFF chechbox
  386. area_thresh_checkbutton = Checkbutton(area_thresh_frame, text="Contour area filter", offvalue=False, onvalue=True, variable=conture_threshold, command=hideContourThreshold)
  387. area_thresh_checkbutton.grid(row=0, column=0,padx=5)
  388.  
  389.     # Contour area filter Maximum slider
  390. area_thresh_min_scale = Scale(area_thresh_frame, from_=0, to=1, orient=HORIZONTAL,length=300, variable=min_contour_area, label="Min area", showvalue=False)
  391. area_thresh_min_scale.bind("<Right>", lambda e: area_thresh_min_scale.set(area_thresh_min_scale.get() + 9 ))
  392. area_thresh_min_scale.bind("<Left>", lambda e: area_thresh_min_scale.set(area_thresh_min_scale.get() - 9 ))
  393.    
  394.     # Contour area filter Minimum slider
  395. area_thresh_max_scale = Scale(area_thresh_frame, from_=0, to=1, orient=HORIZONTAL,length=300, variable=max_contour_area, label="Max area", showvalue=False)
  396. area_thresh_max_scale.bind("<Right>", lambda e: area_thresh_max_scale.set(area_thresh_max_scale.get() + 9 ))
  397. area_thresh_max_scale.bind("<Left>", lambda e: area_thresh_max_scale.set(area_thresh_max_scale.get() - 9 ))
  398.  
  399. #----------- Spacing frame --------------
  400.  
  401. spacing_frame_2 = Frame(all_contour_settings_frame, width=320, height=20)
  402. spacing_frame_2.grid(column=0, row=5)
  403.  
  404. #----------------------------------------
  405.  
  406. # --------------- Create SVG and Recontour button frame ------------------------------
  407. separate_window_frame = Frame(all_contour_settings_frame, width=320, height=40, highlightbackground="black", highlightthickness=1, pady=5)
  408. separate_window_frame.grid(column=0, row=6)
  409. separate_window_frame.grid_propagate(0)
  410. separate_window_frame.columnconfigure(0, weight=0)
  411. separate_window_frame.rowconfigure(0, weight=1)
  412.  
  413. create_SVG_button = Button(separate_window_frame,text="Generate SVG", command=getSVG)
  414. create_SVG_button.grid(column=0, row=0, padx=40)
  415.  
  416. recontour_button_2 = Button(separate_window_frame,text="Recontour image", command=setImages)
  417. recontour_button_2.grid(column=1, row=0,padx=40)
  418.  
  419.  
  420.  
  421.  
  422. #----Close button # don't really think is neccessary------------
  423.  
  424. close_button = Button(tab1, text="Close", command=root.destroy)
  425. #close_button.grid(row=3, column=3)
  426.  
  427.  
  428. # Starts program
  429. root.mainloop()
  430.  
  431.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement