在Python、OpenCV中将对象映射到圆

在Python、OpenCV中将对象映射到圆,python,opencv,Python,Opencv,给定一个包含分割对象的灰度图像的numpy数组。numpy数组具有维度(32,32)。该对象的背景编码为零,对象本身有一个介于(0255)之间的数字。 示例(尺寸(7,7)): #输入 >np.数组([[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,1,2,3,0,0],[0,0,2,2,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]

给定一个包含分割对象的灰度图像的numpy数组。numpy数组具有维度
(32,32)
。该对象的背景编码为零,对象本身有一个介于(0255)之间的数字。 示例(尺寸
(7,7)
):

#输入
>np.数组([[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,1,2,3,0,0],[0,0,2,2,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,
数组([[0,0,0,0,0,0,0,0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 2, 3, 0, 0],
[0, 0, 2, 2, 2, 0, 0],
[0, 0, 1, 2, 3, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0,0,0,0,0,0,0]],dtype=uint8)
numpy数组中的对象可以具有任意形状。 我希望拉伸(扭曲)对象,使其成为一个圆,而不管其先前的形状如何。该圆应填充整个32x32数组。值应进行线性插值。 示例(简化,无线性插值):

#所需输出=带线性插值的圆
数组([[0,0,0,2,0,0,0,0],
[0, 1, 1, 2, 3, 3, 0],
[0, 1, 1, 2, 3, 3, 0],
[2, 2, 2, 2, 2, 2, 2],
[0, 1, 2, 2, 3, 3, 0],
[0, 1, 2, 2, 3, 3, 0],
[0,0,0,2,0,0,0]],dtype=uint8)

我该怎么做。是否有一个OpenCV函数可以将对象扭曲成圆?

让我们将问题分为三个步骤:

  • 将图像大小调整为32x32
  • 将矩阵从正方形重新映射为圆形
  • 修剪边并根据需要调整大小
  • 将图像大小调整为32x32

    您可以使用来为您制作作业。它将执行所有必要的插值,以使图像达到您想要的大小

    square = np.array([[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,1,2,3,0,0],[0,0,2,2,2,0,0],[0,0,1,2,3,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]], dtype=np.uint8)
    resized_image = cv2.resize(square, (32, 32)) 
    

    将矩阵从正方形重新映射到圆形

    从数学上讲,有很多方法可以创建从方阵到圆的变换。这是一个非常有趣的话题。基本上,你必须定义一个函数,从一组点
    [x,y]
    到另一组点
    [u,v]
    ,方志伟提到的一个可能的解决方案是:

    u=x√(x²+y²-x²y²)/√(x²+y²)

    v=y√(x²+y²-x²y²)/√(x²+y²)

    您可以使用此公式和函数来获得所需的转换。但是有一个名为的工具可以为您完成所有工作!通过阅读他们的文档,您可以生成一个简单的代码来进行此转换:

    导入时使用:

    from squircle import to_circle 
    from PIL import Image
    
    打开图像后调用转换:

    circle = to_circle(square)
    

    必要时修剪边缘并调整大小

    现在,您只需修剪矩阵中的所有零,然后重新调整其大小,使所有32x32矩阵中都包含内容。您可以使用的解决方案如下所述:
    circle
    是重新映射的图像。在剪切所有初始行和最终行以及列后,您必须再次将其调整为32x32

    coords = np.argwhere(circle)
    x_min, y_min = coords.min(axis=0)
    x_max, y_max = coords.max(axis=0)
    b = cropped = circle[x_min:x_max+1, y_min:y_max+1]
    resized_cropped_image = cv2.resize(cropped, (32, 32)) 
    

    完整示例
    示例1-使用数组:


    示例2-使用另一个图像:

    你可以在我的Github页面上找到。完整的代码可以在下面看到

    import numpy as np
    import cv2
    import matplotlib.pyplot as plt
    from squircle import to_circle, to_square
    from PIL import Image
    
    square = np.asarray(Image.open('Picture.png').convert('L'))
    #square = np.array([[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,1,2,3,0,0],[0,0,2,2,2,0,0],[0,0,1,2,3,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]], dtype=np.uint8)
    resized_image = cv2.resize(square, (32, 32)) 
    
    circle = to_circle(resized_image)
    
    coords = np.argwhere(circle)
    x_min, y_min = coords.min(axis=0)
    x_max, y_max = coords.max(axis=0)
    b = cropped = circle[x_min:x_max+1, y_min:y_max+1]
    resized_cropped_image = cv2.resize(cropped, (32, 32)) 
    
    
    fig, axs = plt.subplots(2, 2, figsize=(10,10))
    
    axs[0, 0].imshow(square)
    axs[0, 0].set_title('Original')
    
    axs[0, 1].imshow(resized_image)
    axs[0, 1].set_title('Resized to 32x32')
    
    axs[1, 0].imshow(circle)
    axs[1, 0].set_title('Remapped to cicle')
    
    axs[1, 1].imshow(resized_cropped_image)
    axs[1, 1].set_title('Trimmed')