飲料瓶顏色區域擬合

MKT-porter發表於2024-04-13

import cv2
import numpy as np


thresh_gaizi=117
thresh_gaizi_range=3
thresh_yemian=257
thresh_yemian_range=3
thresh_baozhuang=436
thresh_baozhuang_range=3

value_gaizi=0
value_yemian=0
value_baozhuang=0

#對比1
#mask_img=mask_hsv #使用預先標定的顏色摳圖
#對比2
#mask_img=dst #使用Sobel融合後的檢測摳圖
#對比3
#mask_img=edge_output  #使用Canny邊緣檢測演算法的檢測摳圖

mask_use=1  # 1-hsv 2-canny 3-canny


#(c1)是否視窗列印訊息-除錯使用但是會降低檢測速度
debug_print=0 #除錯階段1  正式使用追求速度0
#選擇檢測形狀
detect_what=0#1圓 0矩形
  
#(c2)選擇是否出現標定顏色介面
detect_biaoding=1# 每次換一個光照環境 給1 滑鼠點選顏色區域矯正顏色數值,獲取範圍填寫在color_dist的最大最小中
  
#(c3)選擇檢測多少顏色
#檢測一種顏色 Lower顏色下限數值  Upper顏色上限數值
#color_dist = {'red': {'Lower': np.array([0, 230, 150]), 'Upper': np.array([10, 255, 190])},}
  
#檢測多種顏色-有更多自己往後新增

color_dist = {'red': {'Lower': np.array([160, 80, 150]), 'Upper': np.array([190, 210, 220])},
              'yello': {'Lower': np.array([0, 0, 0]), 'Upper': np.array([170, 160, 80])}
                               }
 
  
hsvshow=0
  
#滑鼠點選函式
def getposHsv(event,x,y,flags,param):
    if event==cv2.EVENT_LBUTTONDOWN:
        print("HSV is",hsvshow[y,x])
  
  
  
  
def getColorBox(shareData,shareLock):
      
    cap = cv2.VideoCapture(0)
    #cv2.namedWindow('imageHSV', 1)
      
    if mask_use==1 and detect_biaoding==1:
        cv2.namedWindow('HSV', 1)
        cv2.setMouseCallback("HSV",getposHsv)#滑鼠函式
      
    while cap.isOpened():
        ret, frame = cap.read()
        if frame is not None:
              
           
            gs_frame = cv2.GaussianBlur(frame, (5, 5), 0)                     # 高斯模糊     
            hsv = cv2.cvtColor(gs_frame, cv2.COLOR_BGR2HSV)                 # 轉化成HSV影像
            global hsvshow
            hsvshow=hsv
            erode_hsv = cv2.erode(hsv, None, iterations=2)                   # 腐蝕 粗的變細
            
            global color_dist
            if mask_use==1:
                #color_dist=color_dist
                pass
            else:
                color_dist = {'red': {'Lower': np.array([0, 190, 140]), 'Upper': np.array([10, 255, 255])} }
                
            for nowcoloe in color_dist:
            
            
            
                #使用純顏色摳圖
                global mask_hsv
                if mask_use==1:
                    mask_hsv = cv2.inRange(erode_hsv, color_dist[nowcoloe]['Lower'], color_dist[nowcoloe]['Upper'])
 
 
 
                # 灰度影像
                gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
 
                 
              
                # 高斯模糊,降低噪聲
                blurred = cv2.GaussianBlur(gray, (3, 3), 0)
 
                 
                # 影像梯度
                #對比1  橫向檢測
                xgrad = cv2.Sobel(blurred, cv2.CV_16SC1, 1, 0)
                absX = cv2.convertScaleAbs(xgrad)   # 轉回uint8
 
                #對比2  縱向檢測
                ygrad = cv2.Sobel(blurred, cv2.CV_16SC1, 0, 1)
                absY = cv2.convertScaleAbs(ygrad)
 
                #對比3  橫+縱檢測
                dst = cv2.addWeighted(absX,0.5,absY,0.5,0)
                  
                #cv2.imshow("absX", absX)
                #cv2.imshow("absY", absY)
                #cv2.imshow("absX_absY", dst)
 
                edge_output = cv2.Canny(xgrad, ygrad, 50, 150)
                cv2.imshow("absX_absY_canny", edge_output)
 
 
                 
                #img = cv2.GaussianBlur(mask_hsv,(3,3),0)
                #canny = cv2.Canny(img, 50, 150)
 
 
                #下面檢測用那個放開那個  預設是1
                mask_img=frame
                
                if mask_use==1:
                #對比1
                    mask_img=mask_hsv #使用預先標定的顏色摳圖erode_hsv
                elif mask_use==2:
                #對比2
                    mask_img=dst #使用Sobel融合後的檢測摳圖
                elif mask_use==3: 
                #對比3
                    mask_img=edge_output  #使用Canny邊緣檢測演算法的檢測摳圖
                 
                 
                #print(colorshow)
                 
                cnts = cv2.findContours(mask_img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
 
                draw_color=(255,255,255)
                
                
                if nowcoloe=="red":
                    draw_color=(0,0,255)
                elif nowcoloe=="yello":
                    draw_color=(0,255,255)
                elif nowcoloe=="green":
                    draw_color=(0,255,0)
                    
                    
                
                    
                    
                    
                image=frame 
                if cnts:
                    cnt = max(cnts, key=cv2.contourArea)
                    c=cnt
                      
                    
                    #函式可以計算面積,也可以使用矩 M[‘m00’]
                    area=cv2.contourArea(c)  
                    #if area<1000:#踢出小邊界
                        #continue


                    perimeter = cv2.arcLength(c,True) #計算周長

                    #hull = cv2.convexHull(cnt) #凸包

                    #最大邊界矩形(包圍盒)
                    draw_rec=0
                    if draw_rec:
                        x,y,w,h = cv2.boundingRect(c)
                        image = cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,255),2)
                    
                    #旋轉矩形
                    draw_rec_ro=0
                    if draw_rec_ro :
                        rect = cv2.minAreaRect(c)
                        box = cv2.boxPoints(rect)
                        box = np.int0(box)
                        cv2.drawContours(image,[box],0,(255,0,255),2)


                    #最小外接圓
                    draw_yuan=0
                    if draw_yuan:
                        (x,y),radius = cv2.minEnclosingCircle(c)
                        center = (int(x),int(y))
                        radius = int(radius)
                        img = cv2.circle(image,center,radius,(0,255,0),2)

                                   

                    # 計算每一個輪廓的中心點
                    M = cv2.moments(c)#計算影像的矩,並返回一個字典  根據這些矩的值可以得到重心
                    M["m00"]=M["m00"]+0.001 #避免除以0
                    cX = int((M["m10"] / M["m00"]))
                    cY = int((M["m01"] / M["m00"]))
                    
                    #print("面積",area,"周長",perimeter,'最小外接圓',radius,'輪廓的中心點',(cX,cY))   

 
                    #檢測圓形
                    
                    if detect_what==1:
                        #用圓擬合目標
                        (x, y), radius = cv2.minEnclosingCircle(cnt)
                        with shareLock:
                            shareData[1]=int(x)
                            shareData[2]=int(y)
                            shareData[3]=int(radius)
                          
                        if debug_print==1:
                            print("r",radius)
                        #畫圓函式  radius 半徑   int(x), int(y) 位置
                        cv2.circle(image, (int(x), int(y)), int(radius), draw_color, 2)
 
 
 
                         
                        pass
                    #檢測矩形
                    else:
                        #
                        # 獲取最小外接矩陣,中心點座標,寬高,旋轉角度
                        rect = cv2.minAreaRect(cnt)
                        ## 獲取矩形四個頂點,浮點型
                        box = cv2.boxPoints(rect)
                        
                        
                        # 取整
                        box = np.int0(box)
                        
                        # 獲取四個頂點座標
                        left_point_x = np.min(box[:, 0])
                        right_point_x = np.max(box[:, 0])
                        top_point_y = np.min(box[:, 1])
                        bottom_point_y = np.max(box[:, 1])
                         
                        left_point_y = box[:, 1][np.where(box[:, 0] == left_point_x)][0]
                        right_point_y = box[:, 1][np.where(box[:, 0] == right_point_x)][0]
                        top_point_x = box[:, 0][np.where(box[:, 1] == top_point_y)][0]
                        bottom_point_x = box[:, 0][np.where(box[:, 1] == bottom_point_y)][0]


             
                        
                        
                        if nowcoloe=="red":
                            #print("red",box[2][0],box[2][1])
         

                            value_gaizi=bottom_point_y
                            #value_yemian=0
                            #value_baozhuang=0
                            if value_gaizi>= (thresh_gaizi-thresh_gaizi_range) and value_gaizi<= (thresh_gaizi+thresh_gaizi_range):
                                cv2.putText(image, str("cap level:ok"), (120,bottom_point_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
                            else:
                                cv2.putText(image, str("cap level:error"), (120,bottom_point_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)

                            
                            cv2.putText(image, str(top_point_y), (50,top_point_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
                            cv2.putText(image, str(bottom_point_y), (50,bottom_point_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
                            
                            
                            pt1=(0,top_point_y)
                            pt2=(left_point_x,top_point_y)                       
                            cv2.line(image, pt1, pt2, color=(0,255,0), thickness=2)
                            
                            pt1=(0,bottom_point_y)
                            pt2=(left_point_x,bottom_point_y)                        
                            cv2.line(image, pt1, pt2, color=(0,255,0), thickness=2)
                        
                        elif nowcoloe=="yello":
                            
                            
           
                            #value_gaizi=bottom_point_y
                            value_yemian=top_point_y
                            value_baozhuang=bottom_point_y
                            
                            if value_yemian>= (thresh_yemian-thresh_yemian_range) and value_yemian<= (thresh_yemian+thresh_yemian_range):
                                cv2.putText(image, str("liquid level:ok"), (120,top_point_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
                            else:
                                cv2.putText(image, str("liquid level:error"), (120,top_point_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
                            
                            if value_baozhuang>= (thresh_baozhuang-thresh_baozhuang_range) and value_baozhuang<= (thresh_baozhuang+thresh_baozhuang_range):
                                cv2.putText(image, str("package level:ok"), (120,bottom_point_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
                            else:
                                cv2.putText(image, str("package level:error"), (120,bottom_point_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)



                            #print("yello",box[0][0],box[0][1])
                            cv2.putText(image, str(top_point_y), (50,top_point_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
                            cv2.putText(image, str(bottom_point_y), (50,bottom_point_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
                            
                            pt1=(0,top_point_y)
                            pt2=(left_point_x,top_point_y)                       
                            cv2.line(image, pt1, pt2, color=(255,255,0), thickness=2)
                            
                            pt1=(0,bottom_point_y)
                            pt2=(left_point_x,bottom_point_y)                        
                            cv2.line(image, pt1, pt2, color=(255,255,0), thickness=2)
                            
                        
                        #print(box)
                        with shareLock:
                            shareData[1]=box[0][0]#右上角h
                            shareData[2]=box[0][1]#右上角w
                            shareData[3]=box[2][0]#左下角h
                            shareData[4]=box[2][1]#左下角w                         
                        #print(rect)
                        if debug_print==1:
                            #print("h",box[0][0]-box[2][0],"w",box[0][1]-box[2][1])
                             
                            h=abs(box[2][0]-box[0][0])
                            w=abs(box[2][1]-box[0][1])
                            #周長
                            zhouchang=(h+w)*2
                             
                            txt = "Length:"+str(zhouchang)+"    w:"+str(w)+"   h:"+str(h)
                            cv2.putText(image, txt, (50,50), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
                             
                            #顏色
                            colorshow=(color_dist[nowcoloe]['Lower']+color_dist[nowcoloe]['Upper'])/2
                             
                            txt = "Color-R G B:"+str(colorshow)
                            cv2.putText(image, txt, (50,100), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
                             
                            #座標點
                            x=int((box[0][0]+box[2][0])/2)
                            y=int((box[0][1]+box[2][1])/2)
                             
                            txt = "Position-x:"+str(x)+"    y:"+str(y)
                            cv2.putText(image, txt, (50,150), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 255), 2)
                             
                             
                            txt ="w:"+str(w)+"   h:"+str(h)
                            cv2.putText(image, txt, (50,200), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2)
                             
                             
                         
 
                          
                        if rect[1][0]<90 and rect[1][1]<90: #剔除掉畫素小於90×90的框 排除干擾
                            pass
                        else:              
                            cv2.drawContours(image, [np.int0(box)], -1, draw_color, 2) 
              
            #為了加快速度 檢測程序連視窗都可以不顯示,影像送給給主執行緒序來顯示
            cv2.imshow("RGB",image)
            key=cv2.waitKey(1)
              
            if key == ord('q') or key == ord('Q'):
                shareData[5]=0
                break
            
            if mask_use==1 and detect_biaoding==1:
                cv2.imshow("HSV",hsv)
                key=cv2.waitKey(1)
                if key == ord('q') or key == ord('Q'):
                    break
  
  
  
 
      
      
      
      
  
   
#單獨測試程式碼
from multiprocessing import Process,Manager
if __name__ == '__main__':
    #程序共享記憶體
    manager=Manager()
    shareData=manager.dict()#共享資料
    shareLock=manager.Lock()       #程序資料鎖
      
    #根據檢測的形狀 資料含義不同
    shareData[1]=0#  圓-x   矩形-左上角h
    shareData[2]=0#  圓-y   矩形-左上角w
    shareData[3]=0#  圓-r   矩形-右下角h
    
    shareData[4]=0#  圓-無   矩形-右下角w
    
    
    shareData[8]=0 #wegiht
    
    shareData[9]=1#  控制標誌 控制檢測程序關閉
      
      
    #開啟程序1
    p1=Process(target=getColorBox,args=(shareData,shareLock)) #必須加,號
    p1.deamon=True  #伴隨主程序關閉而關閉
    p1.start()
      
    #主程序不斷獲取程序1返回的結果
    while 1:
        if shareData[9]==0:#串列埠按退出
            break
          
        #print(shareData[1],shareData[2],shareData[3],shareData[4])
          
       

  

相關文章