import wx
import cv2
import colordetect as cd
import colordraw
class CubeFrame(wx.Frame):
def __init__(self,*args,**kwargs):
super(CubeFrame,self).__init__(*args,**kwargs)
self.SetClientSize(600,680)
self.SetMaxSize((600,680))
self.SetMinSize((600,680))
self.Bind(wx.EVT_IDLE,self.onIDLE)
self.panel = wx.Panel(self, wx.ID_ANY)
labelOne = wx.StaticText(self.panel, wx.ID_ANY, '机器人串口:')
inputTxtOne = wx.TextCtrl(self.panel, wx.ID_ANY, 'COM3')
labelTwo = wx.StaticText(self.panel, wx.ID_ANY, '摄像头串口:')
inputTxtTwo = wx.TextCtrl(self.panel, wx.ID_ANY, '0')
self.Bind(wx.EVT_TEXT,self.onCOM1,inputTxtOne)
self.Bind(wx.EVT_TEXT, self.onCOM2, inputTxtTwo)
self.cap=None
self.index = 0
self.COM2=0
self.COM1="COM3"
self.names=["up.jpg","down.jpg","left.jpg","right.jpg","front.jpg","back.jpg"]
labelThree = wx.StaticText(self.panel, wx.ID_ANY, '魔方:')
choice=wx.Choice(self.panel,choices=["上面","下面","左面","右面","前面","后面"])
choice.SetSelection(self.index)
self.Bind(wx.EVT_CHOICE,self.onChoice,choice)
self.cameraBtn = wx.Button(self.panel, wx.ID_ANY, '拍照保存')
self.cubeBtn = wx.Button(self.panel, wx.ID_ANY, '魔方还原')
openBtn = wx.Button(self.panel, wx.ID_ANY, '打开摄像头')
self.cameraBtn.Disable()
#self.cubeBtn.Disable()
self.Bind(wx.EVT_BUTTON, self.onCamera, self.cameraBtn)
self.Bind(wx.EVT_BUTTON, self.onCube, self.cubeBtn)
self.Bind(wx.EVT_BUTTON,self.onOpen,openBtn)
self.pic=wx.StaticBitmap(self.panel)
self.pic.SetSize((600,500))
img=wx.Bitmap()
img.Create(600,500)
self.pic.SetBitmap(img)
topSizer = wx.BoxSizer(wx.VERTICAL)
inputOneSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
inputOneSizer.Add(labelOne, 0, wx.ALL, 5)
inputOneSizer.Add(inputTxtOne, 1, wx.ALL | wx.EXPAND, 5)
inputOneSizer.Add(labelTwo, 0, wx.ALL, 5)
inputOneSizer.Add(inputTxtTwo, 1, wx.ALL | wx.EXPAND, 5)
inputOneSizer.Add(labelThree, 0, wx.ALL | wx.EXPAND, 5)
inputOneSizer.Add(choice, 1, wx.ALL | wx.EXPAND, 5)
btnSizer.Add(openBtn, 0, wx.ALL, 5)
btnSizer.Add(self.cameraBtn, 0, wx.ALL, 5)
btnSizer.Add(self.cubeBtn, 0, wx.ALL, 5)
topSizer.Add(inputOneSizer, 0, wx.ALL | wx.EXPAND, 5)
topSizer.Add(wx.StaticLine(self.panel), 0, wx.ALL | wx.EXPAND, 5)
topSizer.Add(self.pic, 0, wx.ALL | wx.EXPAND, 5)
topSizer.Add(wx.StaticLine(self.panel), 0, wx.ALL | wx.EXPAND, 5)
topSizer.Add(btnSizer, 0, wx.ALL | wx.CENTER, 5)
self.panel.SetSizer(topSizer)
#topSizer.Fit(self)
self.Show(True)
#打开摄像头按钮点击事件
def onOpen(self,event):
try:
self.cap = cv2.VideoCapture(self.COM2)
if self.cap.isOpened()==False:
self.cap.release()
self.cap.retrieve()
self.cap==None
wx.MessageDialog(self, "打开摄像头失败,检查串口是否正确").ShowModal()
else:
self.cameraBtn.Enable()
except Exception as e:
wx.MessageDialog(self,"打开摄像头失败,检查串口是否正确").ShowModal()
self.cap = None
print("打开摄像头失败")
print(str(e))
def onCOM1(self,event):
self.COM1=event.GetEventObject().GetLineText(0)
#print("COM1:"+self.COM1)
def onCOM2(self,event):
self.COM2=event.GetEventObject().GetLineText(0)
#print("COM2:" + self.COM2)
#选择魔方六面
def onChoice(self,event):
choice=event.GetEventObject()
self.index=choice.GetSelection()
if self.cap:
if self.cap.isOpened()==False:
self.cap.open(self.COM2)
#拍照保存按钮点击事件
def onCamera(self, event):
ret, frame = self.cap.read()
if ret:
cv2.imwrite(self.names[self.index],frame)
self.cap.release()
print(self.names[self.index]+"保存成功")
#魔方还原按钮点击事件
def onCube(self, event):
if self.COM1!="":
try:
cd.analyzeCube(self.COM1)
if self.cap!=None:
self.cap.release()
except Exception as e:
wx.MessageDialog(self, "解析魔方出错,请检查文件是否存在或串口是否正确").ShowModal()
print("解析魔方出错(COM1=%s,COM2=%s)"% (self.COM1,self.COM2))
print(str(e))
#监听摄像头事件
def onIDLE(self,event):
if self.cap:
ret,frame=self.cap.read()
if ret:
#cv2.imshow("img",frame)
self.showImage(frame)
#绘制图像
def showImage(self,img):
height,width=img.shape[:2]
(B,G,R)=cv2.split(img)
bitmap=wx.Bitmap.FromBuffer(width,height,cv2.merge((R,G,B)))
self.pic.SetBitmap(bitmap)
import cv2
import numpy as np
import sys
import serial
from colordraw import *
import math
import json
import kociemba
import time
from multiprocessing import Pool
from concurrent.futures import ThreadPoolExecutor
kernel_15 = np.ones((15,15),np.uint8)#15x15的卷积核
kernel_50 = np.ones((50,50),np.uint8)#50x50的卷积核
draw = np.zeros((4800,6400, 3), dtype="uint8")#创建一个高4800*宽6400画布
#处理图片
def colorMatch(side):
cube_rgb = cv2.imread( side + '.jpg')
cube_gray = cv2.cvtColor(cube_rgb, cv2.COLOR_BGR2GRAY)#颜色转换gray
cube_hsv = cv2.cvtColor(cube_rgb,cv2.COLOR_BGR2HSV)#颜色转换hsv
cube_gray = cv2.adaptiveThreshold(cube_gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)#自适应滤波
#cv2.namedWindow(side,cv2.WINDOW_NORMAL)
#cv2.imshow(side,cube_rgb)
# 白色
lower_white = np.array([0, 0, 201])
upper_white = np.array([180, 50, 255])
white_mask = cv2.inRange(cube_hsv, lower_white, upper_white)
white_erosion = cv2.erode(white_mask, kernel_15, iterations = 1)
white_res = cv2.bitwise_and(cube_rgb, cube_rgb, mask = white_erosion)
#红色
'''lower_red = np.array([0,50,50])
upper_red = np.array([10,255,255])
red_mask0 = cv2.inRange(cube_hsv, lower_red, upper_red)
lower_red = np.array([172, 135, 150])
upper_red = np.array([179, 240, 255])
red_mask1 = cv2.inRange(cube_hsv, lower_red, upper_red)
red_mask = red_mask0 + red_mask1
'''
lower_red = np.array([170, 110, 145])
upper_red = np.array([182, 240, 255])
red_mask = cv2.inRange(cube_hsv, lower_red, upper_red)
red_erosion = cv2.erode(red_mask, kernel_15, iterations = 1)
red_res = cv2.bitwise_and(cube_rgb, cube_rgb, mask = red_erosion)
#橙色
lower_orange = np.array([3, 115, 195])
upper_orange = np.array([9, 190, 255])
orange_mask = cv2.inRange(cube_hsv, lower_orange, upper_orange)
orange_erosion = cv2.erode(orange_mask, kernel_15, iterations = 1)
orange_res = cv2.bitwise_and(cube_rgb, cube_rgb, mask = orange_erosion)
#黄色
lower_yellow = np.array([20, 125, 142])
upper_yellow = np.array([34, 243, 255])
yellow_mask = cv2.inRange(cube_hsv, lower_yellow, upper_yellow)
yellow_erosion = cv2.erode(yellow_mask, kernel_15, iterations = 1)
yellow_res = cv2.bitwise_and(cube_rgb, cube_rgb, mask = yellow_erosion)
#绿色
lower_green = np.array([68,140,120])
upper_green = np.array([82,255,245])
green_mask = cv2.inRange(cube_hsv, lower_green, upper_green)
green_erosion = cv2.erode(green_mask, kernel_15, iterations = 1)
green_res = cv2.bitwise_and(cube_rgb, cube_rgb, mask = green_erosion)
#蓝色
lower_blue = np.array([95, 123, 109])
upper_blue = np.array([124, 253, 240])
blue_mask = cv2.inRange(cube_hsv, lower_blue, upper_blue)
blue_erosion = cv2.erode(blue_mask, kernel_15, iterations = 1)
blue_res = cv2.bitwise_and(cube_rgb, cube_rgb, mask = blue_erosion)
#总掩膜
mask = red_erosion + green_erosion + yellow_erosion + blue_erosion + orange_erosion + white_erosion
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel_50)#开运算分割色块
mask = cv2.erode(mask, kernel_50, iterations = 1)
res = cv2.bitwise_and(cube_hsv, cube_hsv, mask = mask)
edges = cv2.Canny(mask,50,80,apertureSize=5)
points = cv2.findNonZero(edges)
#求得图像最大最小值点
min = np.amin(points, axis=0)#求每列的最小值,axis 0为列,1为行
max = np.amax(points, axis=0)#求每列的最大值,axis 0为列,1为行
#求像素x、y最大最小值
w, h = cube_gray.shape[::-1]#获取cube_gray大小(宽列数w*高行数h)
x_max = max[0][0]
y_max = max[0][1]
x_min = min[0][0]
y_min = min[0][1]
width = int(x_max - x_min)
height = int(y_max - y_min)
#定位中点色块颜色及坐标
def midpoint(x1,y1,x2,y2):
x_mid = int((x1 + x2)/2)
y_mid = h - int(((y1 + y2)/2))
color = res[y_mid, x_mid]
return ([int(color[0]), int(color[1]), int(color[2])])
# midpoint获得每个面九个色块的颜色
mid_1 = midpoint(x_min, y_max, (x_min + int(width/3)), (y_max - int(height/3)))
mid_2 = midpoint((x_min + int(width/3)), y_max, (x_min + int(width*2/3)), (y_max - int(height/3)))
mid_3 = midpoint((x_min + int(width*2/3)), y_max, x_max, (y_max - int(height/3)))
mid_4 = midpoint(x_min, (y_max - int(height/3)), (x_min + int(width/3)), (y_max - int(height*2/3)))
mid_5 = midpoint((x_min + int(width/3)), (y_max - int(height/3)), (x_min + int(width*2/3)), (y_max - int(height*2/3)))
mid_6 = midpoint((x_min + int(width*2/3)), (y_max - int(height/3)), x_max, (y_max - int(height*2/3)))
mid_7 = midpoint(x_min, (y_max - int(height*2/3)), (x_min + int(width/3)), y_min)
mid_8 = midpoint(x_min + int(width/3), (y_max - int(height*2/3)), (x_min + int(width*2/3)), y_min)
mid_9 = midpoint(x_min + int(width*2/3), (y_max - int(height*2/3)), x_max, y_min)
mids = [mid_1, mid_2, mid_3, mid_4, mid_5, mid_6, mid_7, mid_8, mid_9]
s=''
for rgb in mids:#hsv
if ((0<=rgb[0]<=180 ) and (0<=rgb[1]<=50 ) and( 201<=rgb[2]<=255)):#白
s+='D'
elif ((3<=rgb[0]<=9 )and (115<=rgb[1]<=190 )and (195<=rgb[2] <=255)):#澄
s+='B'
elif ((95<=rgb[0] <=124) and (123<=rgb[1]<=253) and (109<=rgb[2]<=240)):#蓝
s+='L'
elif( (68<=rgb[0]<=82) and (140<=rgb[1]<=255) and (120<=rgb[2]<=245)):#绿
s+='R'
elif ((20<=rgb[0]<=34) and (125<=rgb[1]<=243) and(142 <=rgb[2]<=255)):#黄
s+='U'
elif ((170<=rgb[0]<=182)and (110<=rgb[1] <=240 )and (145<=rgb[2]<=255 )):#红
s+='F'
return(s)
#任务: 1.IO密集型(会有cpu空闲的时间)
# 2.计算密集型
#多线程对于IO密集型任务有作用,而计算密集型任务不推荐使用多线程。而其中我们还可以得到一个结论:由于GIL锁,多线程不可能真正实现并行,所谓的并行也只是宏观上并行微观上并发,本质上是由于遇到io操作不断的cpu切换所造成并行的现象。由于cpu切换速度极快,所以看起来就像是在同时执行。
#--问题:没有利用多核的优势
#--这就造成了多线程不能同时执行,并且增加了切换的开销,串行的效率可能更高。
def analyzeCube(port):
time_start=time.time()
side=['up','right','front','down','left','back']
#ps=Pool(6)
#cpu=ps.apply(colorMatch,args=(i,)) # 同步执行
#up_cpu=ps.apply_async(colorMatch,args=('up',)) # 异步执行
#right_cpu=ps.apply_async(colorMatch,args=('right',))
#front_cpu=ps.apply_async(colorMatch,args=('front',))
#down_cpu=ps.apply_async(colorMatch,args=('down',))
#left_cpu=ps.apply_async(colorMatch,args=('left',))
#back_cpu=ps.apply_async(colorMatch,args=('back',))
# 关闭进程池,停止接受其它进程
#ps.close()
# 阻塞进程
#ps.join()
#get_str = up_cpu.get() + right_cpu.get() + front_cpu.get() + down_cpu.get() + left_cpu.get() + back_cpu.get()
#线程池(解决进程池问题)
ts = ThreadPoolExecutor(6)
up_cpu=ts.submit(colorMatch,"up")
down_cpu=ts.submit(colorMatch,"down")
right_cpu =ts.submit(colorMatch,"right")
left_cpu =ts.submit(colorMatch,"left")
front_cpu =ts.submit(colorMatch,"front")
back_cpu =ts.submit(colorMatch,"back")
get_str = up_cpu.result() + right_cpu.result() + front_cpu.result() + down_cpu.result() + left_cpu.result() + back_cpu.result()
print('当前颜色:'+get_str)
solve_str=kociemba.solve(get_str)
print(solve_str)
drawcolor(get_str)
time_end=time.time()
print('所需时间:',time_end-time_start,'s')
#向串口输入指令
ser = serial.Serial(port, 9600, timeout=None)
res=ser.write(solve_str.encode("gbk"))
print("已向串口("+port+")写入"+str(res)+"字节")
1.机器人串口:与机器人通信的串口
2.摄像头串口:默认0代表计算机自带的摄像头,如使用外部设备请尝试1,2,…
3.填好串口后点击打开摄像头即可看见画面
4.选择一个魔方面(up,down,left,right,front,back六个面)进行拍照保存
5.最后点击魔方还原(就会向机器人串口发送通过算法得到的字符串)
当前颜色:BRDBURUFFLBRDRLFLLBLURFBDFRLDUUDDLRBDLRULDUFFFFRUBBDUB
U2 R D' L2 B' R D L2 U' F U' B' U B2 R2 D' L2 F2 D2 B2 U2
6."U2 R D’ L2 B’ R D L2 U’ F U’ B’ U B2 R2 D’ L2 F2 D2 B2 U2"这一串字符将会写入机器人串口中
其中U(up):上面,D(down):下面,L(left):左面,R(right):右面,F(前面),B(back):后面
R:右面顺时针转90度
R’:右面逆时针转90度
R2:右面转180度