<filename>src/segment.py
from __future__ import print_function

import os
import numpy as np
import nibabel as nib
import skfuzzy as fuzz
from sklearn.cluster import KMeans
from multiprocessing import Pool, cpu_count


def create_dir(path):
    if not os.path.isdir(path):
        os.makedirs(path)
    return


def load_nii(path):
    nii = nib.load(path)
    return nii.get_data(), nii.get_affine()


def save_nii(data, path, affine):
    nib.save(nib.Nifti1Image(data, affine), path)
    return


def extract_features(data):
    x_idx, y_idx, z_idx = np.where(data > 0)
    features = []
    for x, y, z in zip(x_idx, y_idx, z_idx):
        features.append([data[x, y, z], x, y, z])
    return np.array(features)


def kmeans_cluster(data, n_clusters):
    features = extract_features(data)
    intensities = features[..., 0].reshape((-1, 1))
    kmeans_model = KMeans(n_clusters=n_clusters, init="k-means++",
                          precompute_distances=True, verbose=0,
                          random_state=7, n_jobs=1,
                          max_iter=1000, tol=1e-6).fit(intensities)

    labels = np.zeros(data.shape)
    for l, f in zip(kmeans_model.labels_, features):
        labels[int(f[1]), int(f[2]), int(f[3])] = l + 1

    return labels


def fuzzy_cmeans_cluster(data, n_clusters):
    features = extract_features(data)
    intensities = features[..., 0].reshape((1, -1))

    cntr, u, u0, d, jm, p, fpc = fuzz.cluster.cmeans(
        intensities, n_clusters, 2, error=1e-6,
        maxiter=1000, init=None, seed=7)
    labels_ = np.argmax(u, axis=0)

    labels = np.zeros(data.shape)
    for l, f in zip(labels_, features):
        labels[int(f[1]), int(f[2]), int(f[3])] = l + 1

    return labels


def get_target_label(labels, data):
    labels_set = np.unique(labels)
    mean_intensities = []
    for label in labels_set[1:]:
        label_data = data[np.where(labels == label)]
        mean_intensities.append(np.mean(label_data))
    target_intensity = np.median(mean_intensities)  # GM
    # target_intensity = np.max(mean_intensities)  # WM
    # target_intensity = np.min(mean_intensities)  # CSF
    target_label = mean_intensities.index(target_intensity) + 1
    return target_label


def unwarp_segment(arg, **kwarg):
    return segment(*arg, **kwarg)


def segment(src_path, dst_path, labels_path=None, method="km"):
    print("Segment on: ", src_path)
    try:
        data, affine = load_nii(src_path)
        n_clusters = 3

        if method == "km":
            # Method 1 - KMeans
            labels = kmeans_cluster(data, n_clusters)
        elif method == "fcm":
            # Method 2 - Fuzzy CMeans
            labels = fuzzy_cmeans_cluster(data, n_clusters)

        target = get_target_label(labels, data)
        gm_mask = np.copy(labels).astype(np.float32)
        gm_mask[np.where(gm_mask != target)] = 0.333
        gm_mask[np.where(gm_mask == target)] = 1.
        data = data.astype(np.float32)
        gm = np.multiply(data, gm_mask)
        save_nii(labels, labels_path, affine)
        save_nii(gm, dst_path, affine)
    except RuntimeError:
        print("\tFalid on: ", src_path)

    return


parent_dir = os.path.dirname(os.getcwd())
data_dir = os.path.join(parent_dir, "data")
data_src_dir = os.path.join(data_dir, "ADNIEnhance")
data_dst_dir = os.path.join(data_dir, "ADNIKMSegment")
data_labels = ["AD", "NC"]
create_dir(data_dst_dir)

data_src_paths, data_dst_paths, labels_paths = [], [], []
for label in data_labels:
    src_label_dir = os.path.join(data_src_dir, label)
    dst_label_dir = os.path.join(data_dst_dir, label)
    create_dir(dst_label_dir)
    for subject in os.listdir(src_label_dir):
        data_src_paths.append(os.path.join(src_label_dir, subject))
        subj_name = subject.split(".")[0]
        dst_subj_dir = os.path.join(dst_label_dir, subj_name)
        create_dir(dst_subj_dir)
        data_dst_paths.append(os.path.join(dst_subj_dir, subject))
        labels_paths.append(os.path.join(dst_subj_dir, subj_name + "_labels.nii.gz"))

method = "km"  # "fcm" or "km"

# Test
# segment(data_src_paths[0], data_dst_paths[0], labels_paths[0])

# Multi-processing
subj_num = len(data_src_paths)
paras = zip(data_src_paths, data_dst_paths,
            labels_paths, [method] * subj_num)
pool = Pool(processes=cpu_count())
pool.map(unwarp_segment, paras)

<filename>src/segment.py
from __future__ import print_function

import os
import numpy as np
import nibabel as nib
import skfuzzy as fuzz
from sklearn.cluster import KMeans
from multiprocessing import Pool, cpu_count


def create_dir(path):
    if not os.path.isdir(path):
        os.makedirs(path)
    return


def load_nii(path):
    nii = nib.load(path)
    return nii.get_data(), nii.get_affine()


def save_nii(data, path, affine):
    nib.save(nib.Nifti1Image(data, affine), path)
    return


def extract_features(data):
    x_idx, y_idx, z_idx = np.where(data > 0)
    features = []
    for x, y, z in zip(x_idx, y_idx, z_idx):
        features.append([data[x, y, z], x, y, z])
    return np.array(features)


def kmeans_cluster(data, n_clusters):
    features = extract_features(data)
    intensities = features[..., 0].reshape((-1, 1))
    kmeans_model = KMeans(n_clusters=n_clusters, init="k-means++",
                          precompute_distances=True, verbose=0,
                          random_state=7, n_jobs=1,
                          max_iter=1000, tol=1e-6).fit(intensities)

    labels = np.zeros(data.shape)
    for l, f in zip(kmeans_model.labels_, features):
        labels[int(f[1]), int(f[2]), int(f[3])] = l + 1

    return labels


def fuzzy_cmeans_cluster(data, n_clusters):
    features = extract_features(data)
    intensities = features[..., 0].reshape((1, -1))

    cntr, u, u0, d, jm, p, fpc = fuzz.cluster.cmeans(
        intensities, n_clusters, 2, error=1e-6,
        maxiter=1000, init=None, seed=7)
    labels_ = np.argmax(u, axis=0)

    labels = np.zeros(data.shape)
    for l, f in zip(labels_, features):
        labels[int(f[1]), int(f[2]), int(f[3])] = l + 1

    return labels


def get_target_label(labels, data):
    labels_set = np.unique(labels)
    mean_intensities = []
    for label in labels_set[1:]:
        label_data = data[np.where(labels == label)]
        mean_intensities.append(np.mean(label_data))
    target_intensity = np.median(mean_intensities)  # GM
    # target_intensity = np.max(mean_intensities)  # WM
    # target_intensity = np.min(mean_intensities)  # CSF
    target_label = mean_intensities.index(target_intensity) + 1
    return target_label


def unwarp_segment(arg, **kwarg):
    return segment(*arg, **kwarg)


def segment(src_path, dst_path, labels_path=None, method="km"):
    print("Segment on: ", src_path)
    try:
        data, affine = load_nii(src_path)
        n_clusters = 3

        if method == "km":
            # Method 1 - KMeans
            labels = kmeans_cluster(data, n_clusters)
        elif method == "fcm":
            # Method 2 - Fuzzy CMeans
            labels = fuzzy_cmeans_cluster(data, n_clusters)

        target = get_target_label(labels, data)
        gm_mask = np.copy(labels).astype(np.float32)
        gm_mask[np.where(gm_mask != target)] = 0.333
        gm_mask[np.where(gm_mask == target)] = 1.
        data = data.astype(np.float32)
        gm = np.multiply(data, gm_mask)
        save_nii(labels, labels_path, affine)
        save_nii(gm, dst_path, affine)
    except RuntimeError:
        print("\tFalid on: ", src_path)

    return


parent_dir = os.path.dirname(os.getcwd())
data_dir = os.path.join(parent_dir, "data")
data_src_dir = os.path.join(data_dir, "ADNIEnhance")
data_dst_dir = os.path.join(data_dir, "ADNIKMSegment")
data_labels = ["AD", "NC"]
create_dir(data_dst_dir)

data_src_paths, data_dst_paths, labels_paths = [], [], []
for label in data_labels:
    src_label_dir = os.path.join(data_src_dir, label)
    dst_label_dir = os.path.join(data_dst_dir, label)
    create_dir(dst_label_dir)
    for subject in os.listdir(src_label_dir):
        data_src_paths.append(os.path.join(src_label_dir, subject))
        subj_name = subject.split(".")[0]
        dst_subj_dir = os.path.join(dst_label_dir, subj_name)
        create_dir(dst_subj_dir)
        data_dst_paths.append(os.path.join(dst_subj_dir, subject))
        labels_paths.append(os.path.join(dst_subj_dir, subj_name + "_labels.nii.gz"))

method = "km"  # "fcm" or "km"

# Test
# segment(data_src_paths[0], data_dst_paths[0], labels_paths[0])

# Multi-processing
subj_num = len(data_src_paths)
paras = zip(data_src_paths, data_dst_paths,
            labels_paths, [method] * subj_num)
pool = Pool(processes=cpu_count())
pool.map(unwarp_segment, paras)

# GM # target_intensity = np.max(mean_intensities)  # WM # target_intensity = np.min(mean_intensities)  # CSF # Method 1 - KMeans # Method 2 - Fuzzy CMeans # "fcm" or "km" # Test # segment(data_src_paths[0], data_dst_paths[0], labels_paths[0]) # Multi-processing