Opencv提取轮廓,对轮廓识别后,判断轮廓形状

'''
@Author: your name
@Date: 2020-02-13 13:30:07
@LastEditTime: 2020-02-20 16:17:34
@LastEditors: Please set LastEditors
@Description: 高斯平滑展示,边缘检测展示,
              能够通过按键时时控制高斯平滑,高斯选择改变后改变高斯图和边缘检测图
              边缘检测通过右侧两个滑条更改检测阈值
              加入圆形检测
'''
import tkinter
import os
import cv2
import numpy
from PIL import Image,ImageTk
from tkinter import filedialog

# global start 全局变量定义初始化开始
#全局变量参数
carmela_hight = 200
carmela_width = 200
#Tkinter元素句柄参数
Source_Img_Label = None
Gray_Img_Label = None
Canny_Img_Label = None
Circles_Img_Label = None
Gaussian_Button = None
Counters_Button = None
Threshold_Min_Scale = None
Threshold_Max_Scale = None
Hough_Parm1_Scale = None
Hough_Parm2_Scale = None
#开关量参数
Gaussian_Enable = False
Counters_Enable = False
#获取当前文件路径
py_path=os.path.abspath(os.path.dirname(__file__))
#global end 全局变量定义初始化结束
#创建窗口对象以及窗口使用变量
root = tkinter.Tk()
Img_Path_String = tkinter.StringVar()
Img_Path_String.set('尚未选择文件')
Dp_Value = tkinter.StringVar()
Dp_Value.set('1')
#窗口使用变量初始化开始
screen_Width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
width = screen_Width//2
height = screen_height//2+50
root_win_par = '%dx%d+%d+%d'% (width, height, (screen_Width-width)/2, (screen_height-height)/2)   

#窗口使用变量初始化结束
def resizeImage(image, width, height, inter=cv2.INTER_AREA):
    size = image.shape
    h, w = size[0], size[1]
    #长边缩放为min_side
    min_side = min(width,height)
    scale = max(w, h) / float(min_side)
    new_w, new_h = int(w/scale), int(h/scale)
    resize_img = cv2.resize(image, (new_w, new_h))
    # 填充至min_side * min_side
    if new_w % 2 != 0 and new_h % 2 == 0:
        top, bottom, left, right = (min_side-new_h)/2, (min_side-new_h)/2, (min_side-new_w)/2 + 1, (min_side-new_w)/2
    elif new_h % 2 != 0 and new_w % 2 == 0:
        top, bottom, left, right = (min_side-new_h)/2 + 1, (min_side-new_h)/2, (min_side-new_w)/2, (min_side-new_w)/2
    elif new_h % 2 == 0 and new_w % 2 == 0:
        top, bottom, left, right = (min_side-new_h)/2, (min_side-new_h)/2, (min_side-new_w)/2, (min_side-new_w)/2
    else:
        top, bottom, left, right = (min_side-new_h)/2 + 1, (min_side-new_h)/2, (min_side-new_w)/2 + 1, (min_side-new_w)/2
    pad_img = cv2.copyMakeBorder(resize_img, int(top), int(bottom), int(left), int(right), cv2.BORDER_CONSTANT, value=[0,0,0]) #从图像边界向上,下,左,右扩的像素数目

    return pad_img

    #窗口使用变量初始化结束
#图片获取通过图片路径显示标签,返回值为cv2.imread 缩放后
def ImageGet():
    #读取图片参数,通过opencv
    Source_Img = cv2.imread(Img_Path_String.get())
    if (Source_Img is None):
        return None
    else:
        pass
        #图片大小更改
        #Source_Img = resizeImage(image=Source_Img,width=carmela_width,height=carmela_hight)
    return Source_Img
#原图片显示刷新
def SourceDisplay(Source_Img):
    global Source_Img_Label
    #RGB图像转换并且显示
    Temp_Img = cv2.cvtColor(Source_Img,cv2.COLOR_BGR2RGB)
    Temp_Img = resizeImage(image=Temp_Img,width=carmela_width,height=carmela_hight)
    Temp_Img = Image.fromarray(Temp_Img)
    Temp_Img = ImageTk.PhotoImage(Temp_Img)    
    if(Source_Img_Label is None):#检测是否是第一次输入图片,是的话创建RGB图片显示Label
        Source_Img_Label = tkinter.Label(root,bg='red',image=Temp_Img,width=carmela_width,height=carmela_hight)
        Source_Img_Label.image = Temp_Img
        Source_Img_Label.place(x=10*1+carmela_width*0,y=40+10*0+carmela_hight*0)
    else:#不是的话更改Label中的图片
        Source_Img_Label.configure(image=Temp_Img)
        Source_Img_Label.image = Temp_Img
#灰度图片显示刷新
def GrayDisply(Source_Img):
    global Gray_Img_Label
    global Gaussian_Enable
    #灰度图片转换
    Temp_Img = cv2.cvtColor(Source_Img,cv2.COLOR_BGR2GRAY)
    if Gaussian_Enable:
        Temp_Img = cv2.GaussianBlur(Temp_Img, (5,5), 0, 0, cv2.BORDER_DEFAULT)#高斯处理
    Temp_Img = resizeImage(image=Temp_Img,width=carmela_width,height=carmela_hight)
    Temp_Img = Image.fromarray(Temp_Img)   
    Temp_Img = ImageTk.PhotoImage(Temp_Img)    
    if (Gray_Img_Label is None):#检测是否是第一次输入图片,是的话创建GRAY图片显示Label
        Gray_Img_Label = tkinter.Label(root,bg='red',image=Temp_Img,width=carmela_width,height=carmela_hight)
        Gray_Img_Label.image = Temp_Img
        Gray_Img_Label.place(x=10*2+carmela_width*1,y=40+10*0+carmela_hight*0)
    else:#不是的话更改Label中的图片
        Gray_Img_Label.configure(image=Temp_Img)
        Gray_Img_Label.image = Temp_Img
#边缘函数显示刷新
def CannyDisply(Source_Img,change = True):
    global Canny_Img_Label,Threshold_Min_Scale,Threshold_Max_Scale
    global Gaussian_Enable,Counters_Enable
    #通过灰度图片边缘提取
    if change:
        Temp_Img = cv2.cvtColor(Source_Img,cv2.COLOR_BGR2GRAY)
    else:
        Temp_Img = Source_Img
        
    if Gaussian_Enable:
        Temp_Img = cv2.GaussianBlur(Temp_Img, (5,5), 0, 0, cv2.BORDER_DEFAULT)#高斯处理
    Temp_Img = cv2.Canny(Temp_Img, Threshold_Min_Scale.get(), Threshold_Max_Scale.get())
    if Counters_Enable:
        contours, hierarchy = cv2.findContours(Temp_Img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 
        Temp_Img = ImageGet() 
        cv2.drawContours(Temp_Img,contours,-1,(255,0,0),3)
        for i in contours:
            ShapeAnalysis(i,Temp_Img)        
        cv2.imshow("",Temp_Img)#调试测试
        print(hierarchy)#调试测试
    Temp_Img = resizeImage(image=Temp_Img,width=carmela_width,height=carmela_hight)
    Temp_Img = Image.fromarray(Temp_Img) 
    Temp_Img = ImageTk.PhotoImage(Temp_Img)    
    if (Canny_Img_Label is None):#检测是否是第一次输入图片,是的话创建GRAY图片显示Label
        Canny_Img_Label = tkinter.Label(root,bg='red',image=Temp_Img,width=carmela_width,height=carmela_hight)
        Canny_Img_Label.image = Temp_Img
        Canny_Img_Label.place(x=10*3+carmela_width*2,y=40+10*0+carmela_hight*0)
    else:#不是的话更改Label中的图片
        Canny_Img_Label.configure(image=Temp_Img)
        Canny_Img_Label.image = Temp_Img
#寻找圆显示刷新
def CircleDisplay(Source_Img):
    global Circles_Img_Label
    #
    Temp_Img = cv2.cvtColor(Source_Img,cv2.COLOR_BGR2GRAY)
    if Gaussian_Enable:
        Temp_Img = cv2.GaussianBlur(Temp_Img, (5,5), 0, 0, cv2.BORDER_DEFAULT)#高斯处理
    #Temp_Img = cv2.Canny(Temp_Img, Threshold_Min_Scale.get(), Threshold_Max_Scale.get())
    CannyDisply(Temp_Img,change=False)
    Temp_Img,Circles = FindCircles(Temp_Img)
    #
    Temp_Img = cv2.cvtColor(Source_Img,cv2.COLOR_BGR2RGB)
    max_index = 0     
    max_r = 0  
    if Circles is None: #显示搜索到的圆的信息
        pass
    else:         
        for index,i in enumerate(Circles[0,:]):
            # draw the outer circle
            cv2.circle(Temp_Img,(i[0],i[1]),i[2],(255,0,0),1)
            # draw the center of the circle
            cv2.circle(Temp_Img,(i[0],i[1]),2,(255,0,0),3)
            cv2.putText( Temp_Img,("R=%d"%( i[2] )),(i[0],i[1]-i[2]),cv2.FONT_HERSHEY_COMPLEX,0.5,(0,255,0) )
            if max_r < i[2]:
                max_r = i[2]
                max_index = index
    #print("%d circles is max:r=%d"%(max_index,max_r))#调试测试
    #FindLines(Temp_Img)
    Temp_Img = resizeImage(image=Temp_Img,width=carmela_width,height=carmela_hight)
    Temp_Img = Image.fromarray(Temp_Img) 
    Temp_Img = ImageTk.PhotoImage(Temp_Img) 
   
    if (Circles_Img_Label is None):#检测是否是第一次输入图片,是的话创建GRAY图片显示Label
        Circles_Img_Label = tkinter.Label(root,bg='red',image=Temp_Img,width=carmela_width,height=carmela_hight)
        Circles_Img_Label.image = Temp_Img
        Circles_Img_Label.place(x=10*1+carmela_width*0,y=40+10*1+carmela_hight*1)
    else:#不是的话更改Label中的图片
        Circles_Img_Label.configure(image=Temp_Img)
        Circles_Img_Label.image = Temp_Img
#轮廓识别
def  ShapeAnalysis(contours,img):
    # 轮廓逼近
    epsilon = 0.01 * cv2.arcLength(contours, True)
    approx = cv2.approxPolyDP(contours, epsilon, True) 
    # 分析几何形状
    corners = len(approx)
    shape_type = ""
    if corners == 3:
        shape_type = "三角形"
    elif corners == 4:
        shape_type = "矩形"
    elif 4 < corners < 10:
        shape_type = "多边形"
    elif 10 < corners:
        shape_type = "圆"
    else:
        shape_type = "未知"
    # 求解中心位置
    mm = cv2.moments(contours)
    cx = int(mm['m10'] / mm['m00'])
    cy = int(mm['m01'] / mm['m00'])
    cv2.circle(img, (cx, cy), 3, (0, 0, 255), -1)

    # 计算面积与周长
    p = cv2.arcLength(contours, True)
    area = cv2.contourArea(contours)
    print("周长: %.3f, 面积: %.3f 形状: %s "% (p, area, shape_type))
#寻找图片中的圆返回值1为图片,返回值2为圆的
def FindCircles(Source_Img):
    dp = int(Dp_Value.get(),base = 10)
    circles = cv2.HoughCircles(Source_Img,cv2.HOUGH_GRADIENT,dp,20,param1=Hough_Parm1_Scale.get(),param2=Hough_Parm2_Scale.get(),minRadius=0,maxRadius=0)
    if not(circles is None):
        circles = numpy.around(circles)
        circles = numpy.uint16(circles)
    return Source_Img,circles
#图片选择按键绑定函数
def AskPicture():
    #图片路径获取
    Picture_Path = filedialog.askopenfilename()
    #显示图片路径,在Img_Path_Text中
    Img_Path_String.set(Picture_Path)
    Source_Img = ImageGet()    
    #检测是否输入确实为图片
    if (Source_Img is None):
        Img_Path_String.set('文件选择错误')
        return
    else:
        #cv2.imshow('',Source_Img)#调试测试
        #原图片显示
        SourceDisplay(Source_Img)
        #灰度图片显示刷新
        GrayDisply(Source_Img)
        #边缘函数显示刷新
        CannyDisply(Source_Img)

        CircleDisplay(Source_Img)      
#阈值绑定函数,阈值更改时调用此函数刷新第三幅图片
def ThresholdChange(self):
    global Source_Img_Label,Gray_Img_Label,Canny_Img_Label,Threshold_Min_Scale,Threshold_Max_Scale
    #图片获取
    Source_Img = ImageGet()
    #检测是否输入确实为图片
    if (Source_Img is None):
        return
    else:
        CannyDisply(Source_Img)
        CircleDisplay(Source_Img)
#高斯处理案件绑定函数
def GaussianChoice():
    global Gaussian_Enable,Gaussian_Button
    if Gaussian_Enable:
        Gaussian_Enable = False
        Gaussian_Button['text']='高斯关'
    else:
        Gaussian_Enable = True
        Gaussian_Button['text']='高斯开'
    #刷新图片
    Source_Img = ImageGet()
    #检测是否输入确实为图片
    if (Source_Img is None):
        return
    else:
        #灰度图片显示刷新
        GrayDisply(Source_Img)
        #边缘函数显示刷新
        CannyDisply(Source_Img)     
#轮廓处理案件绑定函数
def CountersChoice():
    global Counters_Enable,Counters_Button
    if Counters_Enable:
        Counters_Enable = False
        Counters_Button['text']='轮廓关'
    else:
        Counters_Enable = True
        Counters_Button['text']='轮廓开'
    #刷新图片
    Source_Img = ImageGet()
    #检测是否输入确实为图片
    if (Source_Img is None):
        return
    else:
        #灰度图片显示刷新
        GrayDisply(Source_Img)
        #边缘函数显示刷新
        CannyDisply(Source_Img)     
#dp更改函数
def DpValueIncrease():
    temp = int(Dp_Value.get(),base = 10)
    temp = temp + 1
    if temp > 10:
        temp = 10
    Dp_Value.set(str(temp))
def DpValueReduce():
    temp = int(Dp_Value.get(),base = 10)
    temp = temp - 1
    if temp < 1:
        temp = 1
    Dp_Value.set(str(temp))
def HoughParamChange(self):
    #图片获取
    Source_Img = ImageGet()
    #检测是否输入确实为图片
    if (Source_Img is None):
        pass
    else:
        CircleDisplay(Source_Img)
    return 
def HoughDpChange():
    #图片获取
    Source_Img = ImageGet()
    #检测是否输入确实为图片
    if (Source_Img is None):
        pass
    else:
        CircleDisplay(Source_Img)
    return True
#窗口大小及位置设置
root.geometry(root_win_par)
#设置窗口是否可变长、宽,True:可变,False:不可变
root.resizable(width=False, height=True)
root.title('设计')#窗口标题设置
root.iconbitmap(py_path+'\\ico.ico')#窗口图标设置
#显示路径输入框初始化及放置(禁止写入)
tkinter.Entry(root,textvariable=Img_Path_String,borderwidth=1,state=tkinter.DISABLED).place(x=10,y=10,width=width-20-40,height=20)
#路径选取按钮初始化设置
tkinter.Button(root,text='选择',command=AskPicture).place(x=width-45,y=10,width=40,height=20)
#高斯处理按钮初始化设置
Gaussian_Button = tkinter.Button(root,text='高斯关',command=GaussianChoice)
Gaussian_Button.place(x=width-45,y=40,width=40,height=20)
#轮廓处理按钮初始化设置
Counters_Button = tkinter.Button(root,text='轮廓关',command=CountersChoice)
Counters_Button.place(x=width-90,y=40,width=40,height=20)
#阈值滚动条
Threshold_Min_Scale = tkinter.Scale(root,from_=0,to=500,orient=tkinter.VERTICAL,length=height-200,width = 10,command=ThresholdChange)
Threshold_Min_Scale.place(x=width-100,y=90)
tkinter.Label(root,text='Min').place(x=width-100+20,y=60)
Threshold_Min_Scale.set(100)
Threshold_Max_Scale = tkinter.Scale(root,from_=0,to=500,orient=tkinter.VERTICAL,length=height-200,width = 10,command=ThresholdChange)
Threshold_Max_Scale.place(x=width-50,y=90)
tkinter.Label(root,text='Max').place(x=width-50+20,y=60)
Threshold_Max_Scale.set(200)
#霍夫变换参数设置
tkinter.Label(root,text="dp:").place(x=width-100,y=height-200+100)
tkinter.Entry(root,textvariable = Dp_Value ,borderwidth=1,state=tkinter.DISABLED,validate='key',validatecommand= HoughDpChange ).place(x=width-100+30,y=height-200+100,width=20,height=20)
tkinter.Button(root,text = '+',command = DpValueIncrease).place(x=width-100+55,y=height-200+100,width=20,height=20)
tkinter.Button(root,text = '-',command = DpValueReduce).place(x=width-100+78,y=height-200+100,width=20,height=20)
Hough_Parm1_Scale = tkinter.Scale(root,from_=1,to=500,orient=tkinter.HORIZONTAL,length = 100,width = 10,command = HoughParamChange)
Hough_Parm1_Scale.place(x=width-100,y=height-200+120)
Hough_Parm1_Scale.set(50)
Hough_Parm2_Scale = tkinter.Scale(root,from_=1,to=100,orient=tkinter.HORIZONTAL,length = 100,width = 10,command = HoughParamChange)
Hough_Parm2_Scale.place(x=width-100,y=height-200+160)
Hough_Parm2_Scale.set(30)
#窗口主循环
root.mainloop()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值