# 使用相機拍照並在上面使用鼠標畫圖輸出一張雷射切個機能夠使用的檔案 **1. 第一個部分為滑鼠事件、影像處理(mask)以及照相的部分** * 用滑鼠再圖片上畫圖後儲存 http://opencv123.blogspot.com/2015/08/blog-post.html https://blog.csdn.net/sinat_41104353/article/details/85171185 https://steam.oxxostudio.tw/category/python/ai/opencv-video-draw.html https://steam.oxxostudio.tw/category/python/example/image-exif.html * 將圖片上影像遮罩轉換成特定顏色的影像 https://steam.oxxostudio.tw/category/python/ai/opencv-inrange.html 功能說明:在圖片上按下滑鼠左鍵並拖曳畫出線條,畫出線條的顏色為全黑,圖片其他部分為全白,輸出成一張為雷射切割軟體可以使用的檔案需求。 ```python= import cv2 import numpy as np dots = [] # 建立空串列記錄座標 w = 420 h = 240 draw = cv2.imread('image.jpg') # 建立 420x240 的 RGBA 黑色畫布 #mask lower_red = np.array([0,43,46]) upper_red = np.array([1,255,255]) #mask def show_xy(event,x,y,flags,param): global dots, draw # 定義全域變數 if flags == 1: if event == 1: dots.append([x,y]) # 如果拖曳滑鼠剛開始,記錄第一點座標 if event == 4: dots = [] # 如果放開滑鼠,清空串列內容 if event == 0 or event == 4: dots.append([x,y]) # 拖曳滑鼠時,不斷記錄座標 x1 = dots[len(dots)-2][0] # 取得倒數第二個點的 x 座標 y1 = dots[len(dots)-2][1] # 取得倒數第二個點的 y 座標 x2 = dots[len(dots)-1][0] # 取得倒數第一個點的 x 座標 y2 = dots[len(dots)-1][1] # 取得倒數第一個點的 y 座標 cv2.line(draw,(x1,y1),(x2,y2),(0,0,255,255),2) # 畫直線 cv2.imshow('image', draw) cv2.imshow('image', draw) cv2.setMouseCallback('image', show_xy) while True: keyboard = cv2.waitKey(5) # 每 5 毫秒偵測一次鍵盤事件 if keyboard == ord('q'): cv2.destroyAllWindows() break # 如果按下 q 就跳出 if keyboard == ord('r'): draw = cv2.imread('image.jpg') # 如果按下 r 就變成原本畫面的畫布 cv2.imshow('image', draw) if keyboard == ord('s'): #儲存影像 cv2.imwrite('output02.jpg', draw, [cv2.IMWRITE_JPEG_QUALITY, 100]) cv2.imshow('output02.jpg', draw) cv2.waitKey(0) cv2.destroyAllWindows() break if keyboard == ord('m'): #mask取紅色特徵 hsv = cv2.cvtColor(draw, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv, lower_red, upper_red) # 使用 inRange output = cv2.bitwise_and(hsv, hsv, mask = mask ) # 套用影像遮罩 #BGR影象的反轉 dst=~mask #存檔 cv2.imwrite('output02.jpg', dst, [cv2.IMWRITE_JPEG_QUALITY, 100]) cv2.imshow('output02.jpg', dst) cv2.waitKey(0) cv2.destroyAllWindows() break cv2.destroyAllWindows() ``` **2. 第二部分為GUI的部分,在介面上使用open、close、quit、mask按鈕對照相機畫面做處理** * python-用tkinter顯示影像&關閉 https://programming727.pixnet.net/blog/post/20483870-python-%E7%94%A8tkinter%E9%A1%AF%E7%A4%BA%E5%BD%B1%E5%83%8F%26%E9%97%9C%E9%96%89 功能說明:使用tkinter作出基礎的介面,定義出check()、open()、close()、quit()、mask()讓按鈕成功實現功能。 ```python= #-*- coding: UTF-8 -*- import tkinter as tk #大小寫要注意,如果小寫不行就改大寫 import time from PIL import ImageTk, Image, ImageDraw import cv2 import random import numpy as np captrue = cv2.VideoCapture(1) #開啟相機,0為預設筆電內建相機 captrue.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')) #設置影像參數 captrue.set(3,500) #像素 captrue.set(4,500) #像素 img_viode = 'D:\pythoncode\coding\python\Python GUI Tkinter\image.jpg' #影像存放位置 要改 #mask draw = cv2.imread('D:\pythoncode\coding\python\Python GUI Tkinter\image.jpg') # 建立 420x240 的 RGBA 黑色畫布 lower_red = np.array([0,43,46]) upper_red = np.array([1,255,255]) dots = [] # 建立空串列記錄座標 def check(): global captrue if captrue.isOpened(): #判斷相機是否有開啟 open() else: captrue = cv2.VideoCapture(1) captrue.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')) #設置影像參數 captrue.set(3,500) #像素 captrue.set(4,500) #像素 open() #mask def show_xy(event,x,y,flags,param): global dots, draw # 定義全域變數 if flags == 1: if event == 1: dots.append([x,y]) # 如果拖曳滑鼠剛開始,記錄第一點座標 if event == 4: dots = [] # 如果放開滑鼠,清空串列內容 if event == 0 or event == 4: dots.append([x,y]) # 拖曳滑鼠時,不斷記錄座標 x1 = dots[len(dots)-2][0] # 取得倒數第二個點的 x 座標 y1 = dots[len(dots)-2][1] # 取得倒數第二個點的 y 座標 x2 = dots[len(dots)-1][0] # 取得倒數第一個點的 x 座標 y2 = dots[len(dots)-1][1] # 取得倒數第一個點的 y 座標 cv2.line(draw,(x1,y1),(x2,y2),(0,0,255,255),2) # 畫直線 cv2.imshow('image', draw) def open(): global s ret,frame = captrue.read() #取得相機畫面 cv2.imwrite(img_viode,frame) #儲存圖片 img_right = ImageTk.PhotoImage(Image.open(img_viode)) #讀取圖片 label_right.imgtk=img_right #換圖片 label_right.config(image=img_right) #換圖片 s = label_right.after(1, open) #持續執行open方法,1000為1秒 def close(): label_right.after_cancel(s) #結束拍照 label_right.config(image=img) #換圖片 #離開程式 def quit(): top.destroy() captrue.release() def mask(): global dots, draw cv2.imshow('image', draw) cv2.setMouseCallback('image', show_xy) while True: keyboard = cv2.waitKey(5) # 每 5 毫秒偵測一次鍵盤事件 if keyboard == ord('q'): cv2.destroyAllWindows() break # 如果按下 q 就跳出 if keyboard == ord('r'): draw = cv2.imread('D:\pythoncode\coding\python\Python GUI Tkinter\image.jpg') # 如果按下 r 就變成原本畫面的畫布 cv2.imshow('image', draw) if keyboard == ord('s'): #儲存影像 cv2.imwrite('output02.jpg', draw, [cv2.IMWRITE_JPEG_QUALITY, 100]) cv2.imshow('output02.jpg', draw) cv2.waitKey(0) cv2.destroyAllWindows() break if keyboard == ord('m'): #mask取紅色特徵 hsv = cv2.cvtColor(draw, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv, lower_red, upper_red) # 使用 inRange output = cv2.bitwise_and(hsv, hsv, mask = mask ) # 套用影像遮罩 #BGR影象的反轉 dst=~mask #存檔 cv2.imwrite('output02.jpg', dst, [cv2.IMWRITE_JPEG_QUALITY, 100]) cv2.imshow('output02.jpg', dst) cv2.waitKey(0) cv2.destroyAllWindows() break cv2.destroyAllWindows() #創建一個視窗 top = tk.Tk() #視窗名稱 top.title('GUI') #寬:300高:200的視窗,放在寬:600高:300的位置 top.geometry('1200x800') #開啟照片 img= ImageTk.PhotoImage(Image.open('D:\pythoncode\coding\python\Python GUI Tkinter\cameraoff.png')) #要改 #用label來放照片 label_right= tk.Label(top,height=480,width=480,bg ='gray94',fg='blue',image = img) #按鈕 button_1 = tk.Button(top,text = 'Open',bd=4,height=4,width=22,bg ='gray94',command =check) button_2 = tk.Button(top,text = 'Close',bd=4,height=4,width=22,bg ='gray94',command =close) button_3 = tk.Button(top, text = 'Quit',bd=4,height=4,width=22,bg ='gray94', command=quit) button_4 = tk.Button(top, text = 'Mask',bd=4,height=4,width=22,bg ='gray94', command=mask) #位置 label_right.grid(row=1,column=0,padx=20, pady=20, sticky="nw") button_1.grid(row=1, column=0, padx=80, pady=550, sticky="nw") button_2.grid(row=1, column=0, padx=280, pady=550, sticky="nw") button_3.grid(row=1, column=0, padx=480, pady=550, sticky="nw") button_4.grid(row=1, column=0, padx=80, pady=650, sticky="nw") top.mainloop() #執行視窗 ```