2010-09-26 37 views
16

Tôi có một bộ hình ảnh png mà tôi muốn xử lý bằng Python và các công cụ liên quan. Mỗi hình ảnh đại diện cho một đối tượng vật lý có kích thước đã biết.thông tin hình ảnh dọc theo hệ tọa độ cực

Trong mỗi hình ảnh có một tính năng cụ thể của đối tượng tại một vị trí pixel/vật lý nhất định. Vị trí là khác nhau cho mỗi hình ảnh.

Tôi muốn áp đặt hệ tọa độ cực trên một hình ảnh nhất định với nguồn gốc tại vị trí của đối tượng địa lý này.

Sau đó tôi muốn có thể nhận được thông tin sau: - cường độ hình ảnh làm chức năng vị trí hướng tâm cho góc cực đã cho - cường độ hình ảnh làm chức năng vị trí xuyên tâm khi giá trị được tính trung bình trên tất cả góc cực.

Tôi có kinh nghiệm trong lập trình Python và sử dụng nhiều chức năng trong NumPy và SciPy, nhưng tôi là một người mới hoàn thành khi nói đến phân tích hình ảnh.

Tôi sẽ đánh giá cao bất kỳ lời khuyên nào bạn có thể cho tôi về các cách tiếp cận có thể sử dụng để giải quyết vấn đề này.

Cảm ơn bạn.

+0

Từ mô tả của bạn, tất cả điều này có vẻ như toán mảng và không xử lý hình ảnh, và bạn nói rằng bạn đã quen thuộc với mảng toán bằng Python, vì vậy những gì bạn muốn đã trả lời? Đó là, những gì bạn mô tả không thực sự là một câu hỏi xử lý hình ảnh cụ thể, như bạn không cố gắng tìm các đối tượng, cạnh, làm mờ hoặc làm sắc nét, v.v. Bạn có muốn biết làm thế nào để đưa hình ảnh vào Numpy (mà sẽ là bước đầu tiên của cách tiếp cận này)? – tom10

Trả lời

36

Những gì bạn đang mô tả là không chính xác xử lý hình ảnh theo ý nghĩa truyền thống, nhưng nó là khá dễ dàng để làm với NumPy vv

Dưới đây là một ví dụ khá lớn làm một số trong những điều bạn đề cập đến để giúp bạn chỉ đúng hướng ... Lưu ý rằng tất cả các ảnh ví dụ đều hiển thị kết quả cho nguồn gốc ở giữa hình ảnh, nhưng các hàm lấy đối số gốc, vì vậy bạn có thể điều chỉnh trực tiếp mọi thứ cho mục đích của mình.

import numpy as np 
import scipy as sp 
import scipy.ndimage 

import Image 

import matplotlib.pyplot as plt 

def main(): 
    im = Image.open('mri_demo.png') 
    im = im.convert('RGB') 
    data = np.array(im) 

    plot_polar_image(data, origin=None) 
    plot_directional_intensity(data, origin=None) 

    plt.show() 

def plot_directional_intensity(data, origin=None): 
    """Makes a cicular histogram showing average intensity binned by direction 
    from "origin" for each band in "data" (a 3D numpy array). "origin" defaults 
    to the center of the image.""" 
    def intensity_rose(theta, band, color): 
     theta, band = theta.flatten(), band.flatten() 
     intensities, theta_bins = bin_by(band, theta) 
     mean_intensity = map(np.mean, intensities) 
     width = np.diff(theta_bins)[0] 
     plt.bar(theta_bins, mean_intensity, width=width, color=color) 
     plt.xlabel(color + ' Band') 
     plt.yticks([]) 

    # Make cartesian coordinates for the pixel indicies 
    # (The origin defaults to the center of the image) 
    x, y = index_coords(data, origin) 

    # Convert the pixel indices into polar coords. 
    r, theta = cart2polar(x, y) 

    # Unpack bands of the image 
    red, green, blue = data.T 

    # Plot... 
    plt.figure() 

    plt.subplot(2,2,1, projection='polar') 
    intensity_rose(theta, red, 'Red') 

    plt.subplot(2,2,2, projection='polar') 
    intensity_rose(theta, green, 'Green') 

    plt.subplot(2,1,2, projection='polar') 
    intensity_rose(theta, blue, 'Blue') 

    plt.suptitle('Average intensity as a function of direction') 

def plot_polar_image(data, origin=None): 
    """Plots an image reprojected into polar coordinages with the origin 
    at "origin" (a tuple of (x0, y0), defaults to the center of the image)""" 
    polar_grid, r, theta = reproject_image_into_polar(data, origin) 
    plt.figure() 
    plt.imshow(polar_grid, extent=(theta.min(), theta.max(), r.max(), r.min())) 
    plt.axis('auto') 
    plt.ylim(plt.ylim()[::-1]) 
    plt.xlabel('Theta Coordinate (radians)') 
    plt.ylabel('R Coordinate (pixels)') 
    plt.title('Image in Polar Coordinates') 

def index_coords(data, origin=None): 
    """Creates x & y coords for the indicies in a numpy array "data". 
    "origin" defaults to the center of the image. Specify origin=(0,0) 
    to set the origin to the lower left corner of the image.""" 
    ny, nx = data.shape[:2] 
    if origin is None: 
     origin_x, origin_y = nx // 2, ny // 2 
    else: 
     origin_x, origin_y = origin 
    x, y = np.meshgrid(np.arange(nx), np.arange(ny)) 
    x -= origin_x 
    y -= origin_y 
    return x, y 

def cart2polar(x, y): 
    r = np.sqrt(x**2 + y**2) 
    theta = np.arctan2(y, x) 
    return r, theta 

def polar2cart(r, theta): 
    x = r * np.cos(theta) 
    y = r * np.sin(theta) 
    return x, y 


def bin_by(x, y, nbins=30): 
    """Bin x by y, given paired observations of x & y. 
    Returns the binned "x" values and the left edges of the bins.""" 
    bins = np.linspace(y.min(), y.max(), nbins+1) 
    # To avoid extra bin for the max value 
    bins[-1] += 1 

    indicies = np.digitize(y, bins) 

    output = [] 
    for i in xrange(1, len(bins)): 
     output.append(x[indicies==i]) 

    # Just return the left edges of the bins 
    bins = bins[:-1] 

    return output, bins 

def reproject_image_into_polar(data, origin=None): 
    """Reprojects a 3D numpy array ("data") into a polar coordinate system. 
    "origin" is a tuple of (x0, y0) and defaults to the center of the image.""" 
    ny, nx = data.shape[:2] 
    if origin is None: 
     origin = (nx//2, ny//2) 

    # Determine that the min and max r and theta coords will be... 
    x, y = index_coords(data, origin=origin) 
    r, theta = cart2polar(x, y) 

    # Make a regular (in polar space) grid based on the min and max r & theta 
    r_i = np.linspace(r.min(), r.max(), nx) 
    theta_i = np.linspace(theta.min(), theta.max(), ny) 
    theta_grid, r_grid = np.meshgrid(theta_i, r_i) 

    # Project the r and theta grid back into pixel coordinates 
    xi, yi = polar2cart(r_grid, theta_grid) 
    xi += origin[0] # We need to shift the origin back to 
    yi += origin[1] # back to the lower-left corner... 
    xi, yi = xi.flatten(), yi.flatten() 
    coords = np.vstack((xi, yi)) # (map_coordinates requires a 2xn array) 

    # Reproject each band individually and the restack 
    # (uses less memory than reprojection the 3-dimensional array in one step) 
    bands = [] 
    for band in data.T: 
     zi = sp.ndimage.map_coordinates(band, coords, order=1) 
     bands.append(zi.reshape((nx, ny))) 
    output = np.dstack(bands) 
    return output, r_i, theta_i 

if __name__ == '__main__': 
    main() 

gốc Hình ảnh:

MRI Demo

Dự kiến ​​vào tọa độ cực:

Image in Polar Coordinates

Cường như một hàm theo hướng từ trung tâm của hình ảnh: Circular histograms of image intensity

+0

Cảm ơn bạn! Điều đó rất hữu ích. – cytochrome

+1

@ user458738, bạn nên chấp nhận câu trả lời của mình sau đó bằng cách nhấp vào dấu kiểm ở bên trái của nó. –

+0

Thật là một câu trả lời tuyệt vời! – ajwood

1

Dưới đây là quan điểm của tôi sử dụng phương pháp geometric_transform scipy của:

topolar.py

import numpy as np 
from scipy.ndimage.interpolation import geometric_transform 

def topolar(img, order=1): 
    """ 
    Transform img to its polar coordinate representation. 

    order: int, default 1 
     Specify the spline interpolation order. 
     High orders may be slow for large images. 
    """ 
    # max_radius is the length of the diagonal 
    # from a corner to the mid-point of img. 
    max_radius = 0.5*np.linalg.norm(img.shape) 

    def transform(coords): 
     # Put coord[1] in the interval, [-pi, pi] 
     theta = 2*np.pi*coords[1]/(img.shape[1] - 1.) 

     # Then map it to the interval [0, max_radius]. 
     #radius = float(img.shape[0]-coords[0])/img.shape[0] * max_radius 
     radius = max_radius * coords[0]/img.shape[0] 

     i = 0.5*img.shape[0] - radius*np.sin(theta) 
     j = radius*np.cos(theta) + 0.5*img.shape[1] 
     return i,j 

    polar = geometric_transform(img, transform, order=order) 

    rads = max_radius * np.linspace(0,1,img.shape[0]) 
    angs = np.linspace(0, 2*np.pi, img.shape[1]) 

    return polar, (rads, angs) 

Và đây là một số cách sử dụng thử nghiệm:

testpolar.py

from topolar import topolar 
from skimage.data import chelsea 

import matplotlib.pyplot as plt 

img = chelsea()[...,0]/255. 
pol, (rads,angs) = topolar(img) 

fig,ax = plt.subplots(2,1,figsize=(6,8)) 

ax[0].imshow(img, cmap=plt.cm.gray, interpolation='bicubic') 

ax[1].imshow(pol, cmap=plt.cm.gray, interpolation='bicubic') 

ax[1].set_ylabel("Radius in pixels") 
ax[1].set_yticks(range(0, img.shape[0]+1, 50)) 
ax[1].set_yticklabels(rads[::50].round().astype(int)) 

ax[1].set_xlabel("Angle in degrees") 
ax[1].set_xticks(range(0, img.shape[1]+1, 50)) 
ax[1].set_xticklabels((angs[::50]*180/3.14159).round().astype(int)) 

plt.show() 

...và đầu ra:

chelsea in polar coords

Các vấn đề liên quan