1. 程式人生 > >使用opencv從圖片中裁剪出任意形狀的四邊形

使用opencv從圖片中裁剪出任意形狀的四邊形

寫在前面:之前是先得到任意四邊形的最小外接矩形,再使用opencv進行裁剪,但是這樣會引入噪聲。所以在此記錄下,如何直接裁剪原任意四邊形區域。

思路:

1.計算要裁剪區域四邊形的相對水平方向的旋轉角度;

2.將原圖旋轉該角度,以使得要裁剪的區域旋轉到水平方向;

3.將要裁剪區域的座標做相應的轉換,轉換為旋轉後的座標;

4.對該區域進行裁剪。

# -*- coding:utf-8 -*-
import cv2
from math import *
import numpy as np
import time,math
import os
import re

'''旋轉影象並剪裁'''
def rotate(
        img,  # 圖片
        pt1, pt2, pt3, pt4,
        newImagePath
):
    print pt1,pt2,pt3,pt4
    withRect = math.sqrt((pt4[0] - pt1[0]) ** 2 + (pt4[1] - pt1[1]) ** 2)  # 矩形框的寬度
    heightRect = math.sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) **2)
    print withRect,heightRect
    angle = acos((pt4[0] - pt1[0]) / withRect) * (180 / math.pi)  # 矩形框旋轉角度
    print angle

    if pt4[1] > pt1[1]:
        print "順時針旋轉"
    else:
        print "逆時針旋轉"
        angle = -angle

    height = img.shape[0]  # 原始影象高度
    width = img.shape[1]   # 原始影象寬度
    rotateMat = cv2.getRotationMatrix2D((width / 2, height / 2), angle, 1)  # 按angle角度旋轉影象
    heightNew = int(width * fabs(sin(radians(angle))) + height * fabs(cos(radians(angle))))
    widthNew = int(height * fabs(sin(radians(angle))) + width * fabs(cos(radians(angle))))

    rotateMat[0, 2] += (widthNew - width) / 2
    rotateMat[1, 2] += (heightNew - height) / 2
    imgRotation = cv2.warpAffine(img, rotateMat, (widthNew, heightNew), borderValue=(255, 255, 255))

    # 旋轉後圖像的四點座標
    [[pt1[0]], [pt1[1]]] = np.dot(rotateMat, np.array([[pt1[0]], [pt1[1]], [1]]))
    [[pt3[0]], [pt3[1]]] = np.dot(rotateMat, np.array([[pt3[0]], [pt3[1]], [1]]))
    [[pt2[0]], [pt2[1]]] = np.dot(rotateMat, np.array([[pt2[0]], [pt2[1]], [1]]))
    [[pt4[0]], [pt4[1]]] = np.dot(rotateMat, np.array([[pt4[0]], [pt4[1]], [1]]))

    # 處理反轉的情況
    if pt2[1] > pt4[1]:
        pt2[1],pt4[1] = pt4[1],pt2[1]
    if pt1[0] > pt3[0]:
        pt1[0],pt3[0] = pt3[0],pt1[0]

    imgOut = imgRotation[int(pt2[1]):int(pt4[1]), int(pt1[0]):int(pt3[0])]
    cv2.imwrite(newImagePath, imgOut)  # 裁減得到的旋轉矩形框
    return imgRotation  # rotated image


# 根據四點畫原矩形
def drawRect(img,pt1,pt2,pt3,pt4,color,lineWidth):
    cv2.line(img, pt1, pt2, color, lineWidth)
    cv2.line(img, pt2, pt3, color, lineWidth)
    cv2.line(img, pt3, pt4, color, lineWidth)
    cv2.line(img, pt1, pt4, color, lineWidth)

# 讀出檔案中的座標值
def ReadTxt(directory,imageName,last):
    fileTxt = last  # txt檔名
    getTxt = open(fileTxt, 'r')  # 開啟txt檔案
    lines = getTxt.readlines()
    length = len(lines)
    for i in range(0,length):
        items = lines[i].split(',')

        pt1 = [int(items[0]), int(items[1])]
        pt4 = [int(items[2]), int(items[3])]
        pt3 = [int(items[4]), int(items[5])]
        pt2 = [int(items[6]), int(items[7])]

        imgSrc = cv2.imread(imageName)
        rotate(imgSrc,pt1,pt2,pt3,pt4,str(i)+'_'+imageName)


if __name__=="__main__":
    directory = "."
    last = 'image_1210.txt'
    imageName = "image_1210.jpg"
    ReadTxt(directory,imageName,last)