python+opencv多进程实现识别魔方颜色,通过kociemba算法得出算法字符串并画图(附毕设完整视频)

完整毕设成果视频如下:

本科毕业设计转魔方(声音略大)


python+opencv本科毕业设计转魔方(声音略大)
上一篇博客已经给大家讲了鼠标hsv获取魔方颜色阈值方法,具体见 python+opencv 识别魔方照片块颜色并可鼠标获取目标区域hsv值
本次给大家讲讲识别的整套流程(其实是从github上扒下来的),看了一个寒假改了改,改成自己能用的,单进程运算六个面按照他的方法识别其实挺慢的,于是便做了一些改进用了多进程(进程池)的方法,创建六个进程,每个进程分别处理一个面,这样就快多了,原来需要三十秒左右,现在好的时候能到一两秒内,分享出来给大家共享。
先呈现一下效果图:
在这里插入图片描述`d 可以看出,快的时候将近一秒,具体要看cpu了。(注:第一次刚一开始运行的时候会很慢,如果时间很长都没有出结果把它关掉,重新在运行一遍就好啦!)
关于多进程进程池的问题,前段时间冥思苦想,一开始用多线程思路,使用threading模块,具体网上都有参考例子,可以搜一下,例如:https://www.cnblogs.com/tyomcat/p/5486827.html,但是用多线程后出现一个致命问题,并不是想自己想的那样更快,反而慢了,原因应该是网上说的 GIL全局锁,在解释器解释执行 Python 代码时,先要得到这把锁,意味着,任何时候只可能有一个线程在执行代码,其它线程要想获得 CPU 执行代码指令,就必须先获得这把锁,如果锁被其它线程占用了,那么该线程就只能等待,直到占有该锁的线程释放锁才有执行代码指令的可能。
因此,这也就是为什么两个线程一起执行反而更加慢的原因,因为同一时刻,只有一个线程在运行,其它线程只能等待,即使是多核CPU,也没办法让多个线程「并行」地同时执行代码,只能是交替执行,因为多线程涉及到上下文切换、锁机制处理(获取锁,释放锁等),所以,多线程执行不快反慢。
在python里,如果想更多的利用多核cpu内存,还是更多利用多进程处理比较好。
https://blog.csdn.net/topleeyap/article/details/78981848这篇博客里有具体的实现多进程的几种方式,我用的是进程池的方式(Pool):

		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()  

我创建了六个进程:up_cpu、right_cpu、front_cpu、down_cpu、left_cpu、back_cpu
将拍摄的六个面照片依次传入颜色识别函数colorMatch(side):

def colorMatch(side):
    cube_rgb = cv2.imread( side + '.jpg')

这套颜色识别方法,是对六种颜色分别计算出掩膜,将其加和后对整个面进行识别,

	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)  

并且通过开运算和腐蚀函数对图像进行色块分离:
效果图如下:(分别是第一个mask,第二个mask,第三个mask,第四个res图)
在这里插入图片描述可以看出,随着处理,色块分离越来越明显。

	中点色块颜色及坐标
    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])])

此处函数为识别每个面hsv图中九个色块的中点颜色和坐标,供后面使用

# 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]

这是获得九个色块的颜色保存在mids列表中

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)

此功能为将各种点色块hsv转化为字符串供给kociemba算法得到解法
注意主函数里

		#cpu=ps.apply(colorMatch,args=(i,))      # 同步执行
        up_cpu=ps.apply_async(colorMatch,args=('up',))  # 异步执行

注释的是同步执行,后面的是异步执行操作

通过kociemba.solve(get_str)函数就能直接得到kociemba算法还原魔方的字符串了

Tip:
这里有一个小细节,为了让操作员更能清楚的知道识别的颜色对不对,我画了一个draw窗口来显示魔方展开后的颜色样子:
在这里插入图片描述 这个本来想通过多线程来画图,原本想的是六个进程每识别完一个面就能在draw画布画出相应的色块,结果试验后发现我以为的多进程共用参数draw,实际上是调用了六次,并没有实现在同一个画布上画图功能。
冥思苦想想了两天,由一开始从网上查资料开辟共享内存或者Manager方法来实现,结果通通不行,突然想到可以把识别颜色后给出的字符串来转换为对应的颜色:

展示一部分自己写的colordraw .py文件里面开头部分,将字符串转换为对应颜色的画图程序:

def drawcolor(get_str):#URFDLB 传入54个字符 
    #strcolor={'U':(0,255,255),'R':(0,255,0),'F':(0,0,255),'D':(255,255,255),'L':(255,191,0),'B':(0,128,255)}  
    #strcolor="URFDLB"  
    draw_str=[]
    #BGR:
    U=(0,255,255)
    R=(0,255,0)
    F=(0,0,255)
    D=(255,255,255)
    L=(255,191,0)
    B=(0,128,255) 
    for key in get_str:#遍历54个字符中每个字符,i为字符

`
一开始想用字典,把每个字符对应的颜色输进去,结果实际调用的时候发现总是没法一起调用,思考了两天两夜才想到用这个for循环+列表就可以实现了,因为54个块的位置是固定的,所以可以把字符串每个字符依次填入到对应的色块中去,然后去寻找他所对应的颜色就ok啦!
辛辛苦苦写了这么多,希望能对大家应用有些启发~~~~
有什么建议可以在下方评论哦,具体程序见:
链接:python+opencv识别魔方颜色+kociemba算法应用+显示识别效果

  • 16
    点赞
  • 92
    收藏
    觉得还不错? 一键收藏
  • 29
    评论
### 回答1: PythonOpenCV库和MediaPipe工具包是可以一起使用的,以实现手势识别的功能。 首先,需要在Python中安装OpenCV库和MediaPipe工具包。可以使用pip命令来安装它们: ``` pip install opencv-python pip install mediapipe ``` 安装完成后,就可以开始使用了。 首先,导入必要的库: ```python import cv2 import mediapipe as mp ``` 接下来,创建一个MediaPipe的Hand对象和一个OpenCV的VideoCapture对象,用于读取摄像头输入: ```python mp_hands = mp.solutions.hands hands = mp_hands.Hands() cap = cv2.VideoCapture(0) ``` 然后,使用一个循环来读取摄像头输入并进行手势识别: ```python while True: ret, frame = cap.read() if not ret: break frame_RGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results = hands.process(frame_RGB) if results.multi_handedness: for hand_landmarks in results.multi_hand_landmarks: # 在这里可以对hand_landmarks进行处理和识别手势的操作 cv2.imshow('Gesture Recognition', frame) if cv2.waitKey(1) == ord('q'): break ``` 在循环中,首先将读取到的帧转换为RGB格式,然后使用Hands对象的process方法对该帧进行手势识别。得到的结果存储在results变量中。 在对每个检测到的手部进行循环处理时,可以使用hand_landmarks来获取该手的关键点坐标。可以根据这些关键点的位置和运动轨迹来实现手势的识别和分析。 最后,通过cv2.imshow方法显示图像,并使用cv2.waitKey方法等待用户操作。当用户按下"q"键时,循环终止,程序退出。 通过以上步骤,就可以使用PythonOpenCV库和MediaPipe工具包实现手势识别的功能了。当然,实际的手势识别算法和操作需要根据具体需求进行进一步的开发和优化。 ### 回答2: Python OpenCV和MediaPipe结合使用可以实现手势识别。首先,我们需要安装必要的库和工具,包括Pythonopencv-python、mediapipe和其他依赖项。 然后,我们可以使用MediaPipe提供的HandTracking模块来检测手部的关键点。它使用机器学习模型来识别手势,并返回手部关键点的坐标。我们可以通过OpenCV视频捕捉模块读取摄像头的实时图像。 接下来,我们通过应用MediaPipe的HandTracking模块获取手部关键点的坐标,并使用OpenCV将这些坐标绘制到图像上,以便我们可以实时看到手部的位置和动作。 完成这些基本的设置后,我们可以定义特定的手势,例如拇指和食指的指尖接触,作为一个简单的示例。我们可以通过检查特定的关键点之间的距离和角度来识别这种手势。如果关键点之间的距离较小并且角度较小,则我们可以确定手势是拇指和食指的指尖接触。 我们可以使用类似的方法来识别其他手势,比如手掌的张开和闭合,拳头的形成等等。我们可以定义一系列规则和阈值来确定特定手势的识别。 最后,我们可以根据检测到的手势执行特定的操作。例如,当识别到拇指和食指的指尖接触时,我们可以触发相机的快门,实现手势拍照。 总之,PythonOpenCV和MediaPipe结合使用可以实现手势识别。我们可以利用MediaPipe的HandTracking模块检测手部关键点,并使用OpenCV实时绘制手势位置。通过定义特定手势的规则,我们可以识别各种手势并执行相应操作。
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值