一. 介绍  
 OpenCV是最流行的计算机视觉任务库,它是用于机器学习、图像处理等的跨平台开源库,用于开发实时计算机视觉应用程序。  
 CVzone 是一个计算机视觉包,它使用 OpenCV 和 Media Pipe 库作为其核心,使我们易于运行,如手部跟踪、人脸检测、面部标志检测、姿势估计等,以及图像处理和其他计算机视觉。  
 二. 效果  
 
 三. 重点  
 多的我也就我讲了,网络上的其他博主写的也是非常好了,我这里就主要介绍那个避免一次输入多个相同的字母,以及如何一次输入相同的字母.  
 代码如下:  
import  cv2
import  cvzone
from  cvzone. HandTrackingModule import  HandDetector
from  time import  sleep
import  numpy as  np
from  pynput. keyboard import  Controller
cap =  cv2. VideoCapture( 0 ,  cv2. CAP_DSHOW) 
cap. set ( 3 ,  1280 ) 
cap. set ( 4 ,  720 ) 
detector =  HandDetector( detectionCon= 0.8 ) 
keyboard_keys =  [ [ "Q" ,  "W" ,  "E" ,  "R" ,  "T" ,  "Y" ,  "U" ,  "I" ,  "O" ,  "P" ] , 
                 [ "A" ,  "S" ,  "D" ,  "F" ,  "G" ,  "H" ,  "J" ,  "K" ,  "L" ,  ";" ] , 
                 [ "Z" ,  "X" ,  "C" ,  "V" ,  "B" ,  "N" ,  "M" ,  "," ,  "." ,  "/" ] ] 
final_text =  "" 
a =  [ 1 ] 
keyboard =  Controller( ) 
def  draw ( img,  buttonList) : 
    for  button in  buttonList: 
        x,  y =  button. pos
        w,  h =  button. size
        cvzone. cornerRect( img,  ( button. pos[ 0 ] ,  button. pos[ 1 ] , 
                                button. size[ 0 ] ,  button. size[ 0 ] ) ,  20 ,  rt= 0 ) 
        cv2. rectangle( img,  button. pos,  ( int ( x +  w) ,  int ( y +  h) ) ,  ( 255 ,  144 ,  30 ) ,  cv2. FILLED) 
        cv2. putText( img,  button. text,  ( x +  20 ,  y +  65 ) , 
                    cv2. FONT_HERSHEY_PLAIN,  4 ,  ( 0 ,  0 ,  0 ) ,  4 ) 
    return  img
def  transparent_layout ( img,  buttonList) : 
    imgNew =  np. zeros_like( img,  np. uint8) 
    for  button in  buttonList: 
        x,  y =  button. pos
        cvzone. cornerRect( imgNew,  ( button. pos[ 0 ] ,  button. pos[ 1 ] , 
                                   button. size[ 0 ] ,  button. size[ 0 ] ) ,  20 ,  rt= 0 ) 
        cv2. rectangle( imgNew,  button. pos,  ( x +  button. size[ 0 ] ,  y +  button. size[ 1 ] ) , 
                      ( 255 ,  144 ,  30 ) ,  cv2. FILLED) 
        cv2. putText( imgNew,  button. text,  ( x +  20 ,  y +  65 ) , 
                    cv2. FONT_HERSHEY_PLAIN,  4 ,  ( 0 ,  0 ,  0 ) ,  4 ) 
    out =  img. copy( ) 
    alpaha =  0.5 
    mask =  imgNew. astype( bool ) 
    print ( mask. shape) 
    out[ mask]  =  cv2. addWeighted( img,  alpaha,  imgNew,  1  -  alpaha,  0 ) [ mask] 
    return  out
class  Button ( ) : 
    def  __init__ ( self,  pos,  text,  size= [ 85 ,  85 ] ) : 
        self. pos =  pos
        self. size =  size
        self. text =  text
buttonList =  [ ] 
for  k in  range ( len ( keyboard_keys) ) : 
    for  x,  key in  enumerate ( keyboard_keys[ k] ) : 
        buttonList. append( Button( [ 100  *  x +  25 ,  100  *  k +  50 ] ,  key) ) 
while  True : 
    success,  img =  cap. read( ) 
    img =  detector. findHands( img) 
    lmList,  bboxInfo =  detector. findPosition( img) 
    img =  draw( img,  buttonList)   
    if  lmList: 
        for  button in  buttonList: 
            x,  y =  button. pos
            w,  h =  button. size
            if  x <  lmList[ 8 ] [ 0 ]  <  x +  w and  y <  lmList[ 8 ] [ 1 ]  <  y +  h: 
                cv2. rectangle( img,  button. pos,  ( x +  w,  y +  h) , 
                              ( 0 ,  255 ,  255 ) ,  cv2. FILLED) 
                cv2. putText( img,  button. text,  ( x +  20 ,  y +  65 ) , 
                            cv2. FONT_HERSHEY_PLAIN,  4 ,  ( 0 ,  0 ,  0 ) ,  4 ) 
                l,  _,  _ =  detector. findDistance( 8 ,  12 ,  img,  draw= False ) 
                if  l <  15 : 
                    print ( l,  button. text) 
                    a. append( button. text) 
                    print ( a) 
                    if  button. text ==  a[ - 2 ]  or  button. text ==  '/' : 
                        break 
                    else : 
                        keyboard. press( button. text) 
                        cv2. rectangle( img,  button. pos,  ( x +  w,  y +  h) , 
                                      ( 0 ,  255 ,  0 ) ,  cv2. FILLED) 
                        cv2. putText( img,  button. text,  ( x +  20 ,  y +  65 ) , 
                                    cv2. FONT_HERSHEY_PLAIN,  4 ,  ( 0 ,  0 ,  0 ) ,  4 ) 
                        final_text +=  button. text
                        sleep( 0.20 ) 
    cv2. rectangle( img,  ( 25 ,  350 ) ,  ( 700 ,  450 ) , 
                  ( 255 ,  255 ,  255 ) ,  cv2. FILLED) 
    cv2. putText( img,  final_text,  ( 60 ,  425 ) , 
                cv2. FONT_HERSHEY_PLAIN,  4 ,  ( 0 ,  0 ,  0 ) ,  4 ) 
    cv2. imshow( "output" ,  img) 
    cv2. waitKey( 1 ) 
  
 四. 解释代码  
 主要就是增加了两个判断,如下,当两个手指的距离小于15才打印距离,减小了输出区的冗余,增加了一个列表 来存储小于15距离的字母,当列表里面的最后一个字母与当前的字母相同的时候就不输出,直接跳出,只打印一个字母,这就是去重的思想.  
 第二个就是增加一个无意义的字母,当输入这个字母的时候,什么都不用做,用来可以输入重复的字母.这里我选择了==/==作为无意义的字母,当然你也可以选择其他的符号.  
                if  l <  15 : 
                    print ( l,  button. text) 
                    a. append( button. text) 
                    print ( a) 
                    if  button. text ==  a[ - 2 ]  or  button. text ==  '/' : 
                        break 
                    else : 
                        keyboard. press( button. text) 
                        cv2. rectangle( img,  button. pos,  ( x +  w,  y +  h) , 
                                      ( 0 ,  255 ,  0 ) ,  cv2. FILLED) 
                        cv2. putText( img,  button. text,  ( x +  20 ,  y +  65 ) , 
                                    cv2. FONT_HERSHEY_PLAIN,  4 ,  ( 0 ,  0 ,  0 ) ,  4 ) 
                        final_text +=  button. text
                        sleep( 0.20 ) 
  
 五. 其他的说明  
 手指关节的对应的数字  
 
 知识体系  
 
 六. 这个就是我自己改进后的代码,希望大家共同学习提高.