__all__ = ['invariant_image_similarity',
'convolve_image']
import math
from tempfile import mktemp
import numpy as np
import pandas as pd
from .. import utils
from ..core import ants_image as iio
[docs]def invariant_image_similarity(image1, image2,
local_search_iterations=0, metric='MI',
thetas=np.linspace(0,360,5),
thetas2=np.linspace(0,360,5),
thetas3=np.linspace(0,360,5),
scale_image=1, do_reflection=False,
txfn=None, transform='Affine'):
"""
Similarity metrics between two images as a function of geometry
Compute similarity metric between two images as image is rotated about its
center w/ or w/o optimization
ANTsR function: `invariantImageSimilarity`
Arguments
---------
image1 : ANTsImage
reference image
image2 : ANTsImage
moving image
local_search_iterations : integer
integer controlling local search in multistart
metric : string
which metric to use
MI
GC
thetas : 1D-ndarray/list/tuple
numeric vector of search angles in degrees
thetas2 : 1D-ndarray/list/tuple
numeric vector of search angles in degrees around principal axis 2 (3D)
thetas3 : 1D-ndarray/list/tuple
numeric vector of search angles in degrees around principal axis 3 (3D)
scale_image : scalar
global scale
do_reflection : boolean
whether to reflect image about principal axis
txfn : string (optional)
if present, write optimal tx to .mat file
transform : string
type of transform to use
Rigid
Similarity
Affine
Returns
-------
pd.DataFrame
dataframe with metric values and transformation parameters
Example
-------
>>> import ants
>>> img1 = ants.image_read(ants.get_ants_data('r16'))
>>> img2 = ants.image_read(ants.get_ants_data('r64'))
>>> metric = ants.invariant_image_similarity(img1,img2)
"""
if transform not in {'Rigid', 'Similarity', 'Affine'}:
raise ValueError('transform must be one of Rigid/Similarity/Affine')
if image1.pixeltype != 'float':
image1 = image1.clone('float')
if image2.pixeltype != 'float':
image2 = image2.clone('float')
if txfn is None:
txfn = mktemp(suffix='.mat')
# convert thetas to radians
thetain = (thetas * math.pi) / 180.
thetain2 = (thetas2 * math.pi) / 180.
thetain3 = (thetas3 * math.pi) / 180.
image1 = utils.iMath(image1, 'Normalize')
image2 = utils.iMath(image2, 'Normalize')
idim = image1.dimension
fpname = ['FixedParam%i'%i for i in range(1,idim+1)]
if not do_reflection:
libfn = utils.get_lib_fn('invariantImageSimilarity_%s%iD' % (transform, idim))
r1 = libfn(image1.pointer,
image2.pointer,
list(thetain),
list(thetain2),
list(thetain3),
local_search_iterations,
metric,
scale_image,
int(do_reflection),
txfn)
r1 = np.asarray(r1)
pnames = ['Param%i'%i for i in range(1,r1.shape[1])]
pnames[(len(pnames)-idim):len(pnames)] = fpname
r1 = pd.DataFrame(r1, columns=['MetricValue']+pnames)
return r1, txfn
else:
txfn1 = mktemp(suffix='.mat')
txfn2 = mktemp(suffix='.mat')
txfn3 = mktemp(suffix='.mat')
txfn4 = mktemp(suffix='.mat')
libfn = utils.get_lib_fn('invariantImageSimilarity_%s%iD' % (transform, idim))
## R1 ##
r1 = libfn(image1.pointer,
image2.pointer,
list(thetain),
list(thetain2),
list(thetain3),
local_search_iterations,
metric,
scale_image,
0,
txfn1)
r1 = np.asarray(r1)
pnames = ['Param%i'%i for i in range(1,r1.shape[1])]
pnames[(len(pnames)-idim):len(pnames)] = fpname
r1 = pd.DataFrame(r1, columns=['MetricValue']+pnames)
## R2 ##
r2 = libfn(image1.pointer,
image2.pointer,
list(thetain),
list(thetain2),
list(thetain3),
local_search_iterations,
metric,
scale_image,
1,
txfn2)
r2 = np.asarray(r2)
r2 = pd.DataFrame(r2, columns=['MetricValue']+pnames)
## R3 ##
r3 = libfn(image1.pointer,
image2.pointer,
list(thetain),
list(thetain2),
list(thetain3),
local_search_iterations,
metric,
scale_image,
2,
txfn3)
r3 = np.asarray(r3)
r3 = pd.DataFrame(r3, columns=['MetricValue']+pnames)
## R4 ##
r4 = libfn(image1.pointer,
image2.pointer,
list(thetain),
list(thetain2),
list(thetain3),
local_search_iterations,
metric,
scale_image,
3,
txfn4)
r4 = np.asarray(r4)
r4 = pd.DataFrame(r4, columns=['MetricValue']+pnames)
rmins = [np.min(r1.iloc[:,0]), np.min(r2.iloc[:,0]), np.min(r3.iloc[:,0]), np.min(r4.iloc[:,0])]
ww = np.argmin(rmins)
if ww == 0:
return r1, txfn1
elif ww == 1:
return r2, txfn2
elif ww == 2:
return r3, txfn3
elif ww == 3:
return r4, txfn4
[docs]def convolve_image(image, kernel_image, crop=True):
"""
Convolve one image with another
ANTsR function: `convolveImage`
Arguments
---------
image : ANTsImage
image to convolve
kernel_image : ANTsImage
image acting as kernel
crop : boolean
whether to automatically crop kernel_image
Returns
-------
ANTsImage
Example
-------
>>> import ants
>>> fi = ants.image_read(ants.get_ants_data('r16'))
>>> convimg = ants.make_image( (3,3), (1,0,1,0,-4,0,1,0,1) )
>>> convout = ants.convolve_image( fi, convimg )
>>> convimg2 = ants.make_image( (3,3), (0,1,0,1,0,-1,0,-1,0) )
>>> convout2 = ants.convolve_image( fi, convimg2 )
"""
if not isinstance(image, iio.ANTsImage):
raise ValueError('image must be ANTsImage type')
if not isinstance(kernel_image, iio.ANTsImage):
raise ValueError('kernel must be ANTsImage type')
orig_ptype = image.pixeltype
if image.pixeltype != 'float':
image = image.clone('float')
if kernel_image.pixeltype != 'float':
kernel_image = kernel_image.clone('float')
if crop:
kernel_image_mask = utils.get_mask(kernel_image)
kernel_image = utils.crop_image(kernel_image, kernel_image_mask)
kernel_image_mask = utils.crop_image(kernel_image_mask, kernel_image_mask)
kernel_image[kernel_image_mask==0] = kernel_image[kernel_image_mask==1].mean()
libfn = utils.get_lib_fn('convolveImageF%i' % image.dimension)
conv_itk_image = libfn(image.pointer, kernel_image.pointer)
conv_ants_image = iio.ANTsImage(pixeltype=image.pixeltype, dimension=image.dimension,
components=image.components, pointer=conv_itk_image)
if orig_ptype != 'float':
conv_ants_image = conv_ants_image.clone(orig_ptype)
return conv_ants_image