(Python)如何旋转图像以使特征垂直?

(Python)如何旋转图像以使特征垂直?,python,arrays,image,rotation,2d,Python,Arrays,Image,Rotation,2d,我想旋转一个图像(比如下面的图像),使它的一个特征(类似于一条线)变得垂直。然而,我似乎找不到一种用Python编程的方法。 旋转本身可以通过操作完成 下面的第一部分是解决原始问题中示例场景的问题(有一个拉长的数据blob),请参阅下面更一般(但更慢)的方法。希望这有帮助 第一种方法:要找到轴以及线的角度,我建议对非零值使用PCA: from scipy.ndimage.interpolation import rotate #from skimage.transform import rot

我想旋转一个图像(比如下面的图像),使它的一个特征(类似于一条线)变得垂直。然而,我似乎找不到一种用Python编程的方法。

旋转本身可以通过操作完成

下面的第一部分是解决原始问题中示例场景的问题(有一个拉长的数据blob),请参阅下面更一般(但更慢)的方法。希望这有帮助


第一种方法:要找到轴以及线的角度,我建议对非零值使用PCA:

from scipy.ndimage.interpolation import rotate
#from skimage.transform import rotate ## Alternatively
from sklearn.decomposition.pca import PCA ## Or use its numpy variant
import numpy as np

def verticalize_img(img):
    """
    Method to rotate a greyscale image based on its principal axis.

    :param img: Two dimensional array-like object, values > 0 being interpreted as containing to a line
    :return rotated_img: 
    """# Get the coordinates of the points of interest:
    X = np.array(np.where(img > 0)).T
    # Perform a PCA and compute the angle of the first principal axes
    pca = PCA(n_components=2).fit(X)
    angle = np.arctan2(*pca.components_[0])
    # Rotate the image by the computed angle:
    rotated_img = rotate(img,angle/pi*180-90)
    return rotated_img
通常,此函数也可以写成一行:

rotated_img = rotate(img,np.arctan2(*PCA(2).fit(np.array(np.where(img > 0)).T).components_[0])/pi*180-90)
下面是一个例子:

from matplotlib import pyplot as plt
# Example data:
img = np.array([[0,0,0,0,0,0,0],
                [0,1,0,0,0,0,0],
                [0,0,1,1,0,0,0],
                [0,0,0,1,1,0,0],
                [0,0,1,0,0,1,0],
                [0,0,0,0,0,0,1]])
# Or alternatively a straight line:
img = np.diag(ones(15))
img = np.around(rotate(img,25))

# Or a distorted blob:
from sklearn import cluster, datasets
X, y = datasets.make_blobs(n_samples=100, centers = [[0,0]])
distortion = [[0.6, -0.6], [-0.4, 0.8]]
theta = np.radians(20)
rotation = np.array(((cos(theta),-sin(theta)), (sin(theta), cos(theta))))
X =  np.dot(np.dot(X, distortion),rotation)
img = np.histogram2d(*X.T)[0] # > 0 ## uncomment for making the example binary

rotated_img = verticalize_img(img)
# Plot the results
plt.matshow(img)
plt.title('Original')
plt.matshow(rotated_img)
plt.title('Rotated'))
请注意,对于高噪声数据或没有清晰方向的图像,此方法将产生任意旋转

下面是一个示例输出:


第二种方法:在更复杂的设置中澄清实际任务后确定(参见注释),这里是基于模板匹配的第二种方法:

from matplotlib import pyplot as plt
import numpy as np
import pandas
from scipy.ndimage.interpolation import rotate
from scipy.signal import correlate2d#, fftconvolve
# Data from CSV file:
img = pandas.read_csv('/home/casibus/testdata.csv')
# Create a template:
template = np.zeros_like(img.values)
template[:,int(len(template[0])*1./2)] = 1
suggested_angles = np.arange(0,180,1) # Change to any resolution you like
overlaps = [np.amax(correlate2d(rotate(img,alpha,reshape=False),template,mode='same')) for alpha in suggested_angles]
# Determine the angle resulting in maximal overlap and rotate:
rotated_img = rotate(img.values,-suggested_angles[np.argmax(overlaps)])
plt.matshow(rotated_img)
plt.matshow(template)

亲爱的Jojo,非常感谢您的详细回答。它似乎解决了问题,但对于嘈杂的数据(如您所述)它失败了,不幸的是,这是我的大部分数据。亲爱的Bella_Ciao_gr,您能提供一个示例数组吗?谢谢您的关注,Jojo。这里有一个链接到我的文件:好的,那当然是一个非常不同的情况。这里有多条条纹,要让我的函数工作,你需要先提取其中一条条纹。这里有一个非常实用的方法:我建议使用模板(即垂直线图像)并旋转数据,只要重叠(根据峰值scipy.signal.correlation2d)最大化。这给了你一个角度。如果你有问题,我以后可能会抽出时间帮你解决。给你!我没有对不同的例子进行测试,它最终的旋转方式可能会有错误。在这种情况下,试着去掉负号。希望能有帮助。