cv2 五边形矫正,python ,多边形透视变换

#图像透视变换--矫正
#根据最大的5边形进行透视变换
#获取最大和最次长   周长对应的轮廓
#该轮廓进行5边形拟合逼近
#进行透视变换:应用两线交点
import numpy as np
import cv2


#大津阈值法 OSTU
def myApprox(con,pointnum=5):# con为预先得到的最大轮廓
    num = 0.001
    # 初始化时不需要太小,因为四边形所需的值并不很小
    ep = num * cv2.arcLength(con, True)
    con = cv2.approxPolyDP(con, ep, True)
    while (1):
        if len(con) == pointnum:#防止程序崩溃设置的==pointnum
            break
        else:
            num = num * 1.5
            if num >2:
                break
            ep = num * cv2.arcLength(con, True)
            con = cv2.approxPolyDP(con, ep, True)
            continue
    return con

#多边形矫正
def Polygon_correction(img):
    if len(img.shape) > 2:
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    contours, hierarchy = cv2.findContours(img, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    perimeter_list, area_list, cnt_list, center_lsit, box_list = [], [], [], [], []
    ori_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    ori_w,ori_h = ori_img.shape[0],ori_img.shape[1]
    print('ori_w,ori_h:',ori_w,ori_h)

    #ori_img = cv2.drawContours(ori_img, contours, -1, (0, 0, 255), 2)
    cv2.imshow('binary7', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    #筛选面积最大的三个候选轮廓
    if len(contours) > 0:
        cnts = sorted(contours,
                      key=cv2.contourArea,  # 根据该函数计算的结果排序
                      reverse=True)
        cnts = cnts[:2]
        docCnt =None
        x, y, w, h = 0,0,ori_w,ori_h
        for cnt in cnts:
            #逼近法五边形拟合
            approx =myApprox(cnt, pointnum=5)
            if len(approx)==5:
                docCnt = approx
                x, y, w, h = cv2.boundingRect(docCnt) #左上角,w,h
                # 绘制矩形
                #cv2.rectangle(ori_img, (x, y + h), (x + w, y), (0, 255, 255))
                break

        #获取得到五边形边框五个原始点
        if not docCnt is None:
            points = [] #逆时针旋转排序,五个点
            for doc in docCnt:
                peak = doc[0]
                # 在角点绘制小圆圈
                #cv2.circle(ori_img, tuple(peak), 10, (0, 0, 255), 2) #橙色
                points.append(tuple(peak))

            p1, p2, p3, p4, p5 = points[0], points[1], points[2], points[3], points[4]
            #求四点确定的两条线段的交点,p1,p2,crossp,p5 作为ori转移矩阵前坐标点
            from util import get_crosss_point
            crossp = get_crosss_point(p2, p3, p4, p5)
            #如果有交点,让交点作为四个点之一,如果无交点则选择点3或则点4即可
            if crossp is not None:
                src = np.float32([p1,p2,crossp,p5])
                #外接矩阵,水平垂直矩形
                afterp1 = (x, y)
                afterp2 = (x, y + h-1)
                afterpcrossp = (x + w-1, y + h-1)
                afterp5 = (x + w-1, y)
                afterpoints = np.float32([afterp1, afterp2, afterpcrossp, afterp5])
            else:
                src = np.float32([p1,p2,p3,p5])#存在一定误差
                #根据自己需求得到多边形点
                xmin, ymin = np.array(points)[:, 0].min(), np.array(points)[:, 1].min()
                xmax, ymax = np.array(points)[:, 0].max(), np.array(points)[:, 1].max()
                sigma = (xmax - p3[0] + ymax - p4[1])/2
                sigma = int(sigma)

                afterp1 = (xmin, ymin)
                afterp2 = (xmin, ymax)
                afterp3 = (xmax - sigma, ymax)
                afterp4 = (xmax, ymax - sigma)
                afterp5 = (xmax, ymin)
                afterpoints = [afterp1, afterp2, afterp3,afterp5]

            print("原始点:", src)
            print("after点:",afterpoints)

            m = cv2.getPerspectiveTransform(src,afterpoints)
            result = cv2.warpPerspective(ori_img, m,(ori_h,ori_w))  # 透视变换

            cv2.circle(result, afterp1, 5, (0, 255, 0), 2)
            cv2.circle(result, afterp2, 5, (0, 255, 0), 2)
            cv2.circle(result, afterpcrossp, 5, (0, 255, 0), 2)
            cv2.circle(result, afterp5, 5, (0, 255, 0), 2)
            print(result.shape)
            cv2.polylines(result,[np.array(afterpoints, np.int32)], True,(255, 255, 0),1)
            cv2.imshow('result', result)
            cv2.waitKey(0)
            cv2.destroyAllWindows()
            return result
        else:
            return img
    else:
        return img



if __name__ == '__main__':
    img = cv2.imread('./data/binary7.png')#二值图
    afterPolygonimg = Polygon_correction(img)
    


 cv2 五边形矫正,python ,多边形透视变换_第1张图片

 

cv2 五边形矫正,python ,多边形透视变换_第2张图片

 ps:求交点函数,链接为:(85条消息) python 已知四点,两条线,求交点_Lee魅儿的博客-CSDN博客

你可能感兴趣的:(python,图像处理,opencv)