OpenCV透视变换-不对原图裁剪

前言:

最近在做透视变换,初次尝试是使用Pillow的transform方法,但是该方法在变换以后,由于需要提前设置变换后的图像尺寸,所以导致变换后的图像超出尺寸的部分会发生裁剪问题,这个现象不太适合我的目的,我的目的是对png图进行透视变换,然后贴在一张图上。以下是pil的方式

 

from PIL import Image

import numpy


def find_coeffs(pa, pb):
    matrix = []

    for p1, p2 in zip(pa, pb):
        matrix.append([p1[0], p1[1], 1, 0, 0, 0, -p2[0]*p1[0], -p2[0]*p1[1]])
        matrix.append([0, 0, 0, p1[0], p1[1], 1, -p2[1]*p1[0], -p2[1]*p1[1]])

    A = numpy.matrix(matrix, dtype=numpy.float)
    B = numpy.array(pb).reshape(8)
    res = numpy.dot(numpy.linalg.inv(A.T * A) * A.T, B)

    return numpy.array(res).reshape(8)


# test.png is a 256x256 white square
img = Image.open("./images/test.png")

# 根据原始点和目标点,求得变换矩阵
coeffs = find_coeffs(
[(0, 0), (256, 0), (256, 256), (0, 256)],
[(15, 115), (140, 20), (140, 340), (15, 250)])

img.transform((300, 400), Image.PERSPECTIVE, coeffs,Image.BICUBIC).show()

 

后来用了opencv中的方法,这个方法不会对图像进行裁剪,但是图像会出现一些多余的透明区域,因此再进行一步根据像素值非0进行裁剪即可

import cv2
import numpy as np

img = cv2.imread('sample.png')

height, width, channel = img.shape

# 判断是不是四通道,如果不是需要转换
if channel != 4:
    # 创建一个具有4通道(RGBA)的目标图像
    rgba_image = np.zeros((height, width, 4), dtype=np.uint8) 
    # 将RGB图像的通道复制到RGBA图像中 
    rgba_image[:, :, :3] = rgb_image 
    # 初始化Alpha通道为不透明(255) 
    rgba_image[:, :, 3] = 255 # 设置Alpha通道 
    img = rgba_image

# 原目标的四个点位置,分别对应,左上角,右上角,左下角,右下角
src = np.float32([[0,0], [width, 0], [0, height], [width, height]])
#变换后的四个顶点位置,设置随机值
left_top_h = random.randint(0, int(0.35*height))
left_top_w = random.randint(0, int(0.35*width))

right_top_h = random.randint(0, int(0.35*height))
right_top_w = random.randint(int(0.65*width), width)

left_button_h = random.randint(int(0.65*height), height)
left_button_w = random.randint(0, int(0.35*width))

right_button_h = random.randint(int(0.65*height), height)
right_button_w = random.randint(int(0.65*width), width)

dst = np.float32([[left_top_w, left_top_h], [right_top_w, right_top_h], [left_button_w, left_button_h], [right_button_w, right_button_h]])

matrix = cv2.getPerspectiveTransform(src, dst)
imgOutput = cv2.warpPerspective(img, matrix, (width, height))

# 对结果进行裁剪
# 查找不透明像素的边界 
non_transparent_pixels = cv2.findNonZero(imgOutput[:, :, 3]) 
x, y, w, h = cv2.boundingRect(non_transparent_pixels) 
# 裁剪图像 
cropped_image = imgOutput[y:y+h, x:x+w]

# 保存结果
cv2.imwrite('transform.png', imgOutput)


# 注意,以上是opencv的方式,如果你使用pil读取图像,返回也需要pil格式,就需要对其进行变换
# 假设pil读取png图像
pil_img = Image.open('sample.png').convert('RGBA')
img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGBA2BGRA)

# 保存的时候将cv2格式转为pil

imgOutput = cv2.cvtColor(imgOutput, cv2.COLOR_BGRA2RGBA)
imgOutput = Image.fromarray(imgOutput)

 

posted @ 2023-11-08 18:14  海_纳百川  阅读(113)  评论(0编辑  收藏  举报
本站总访问量