from __future__ import print_function
import SimpleITK as sitk
import numpy as np
import os
import sys
import pickle
from random import shuffle
from skimage.transform import resize, rotate, rescale
from skimage.io import imsave, imread
from sklearn.feature_extraction.image import extract_patches as sk_extract_patches, reconstruct_from_patches_2d
from skimage.util.shape import view_as_windows
import cv2 as cv
from skimage import img_as_ubyte

#import scipy
import imutils

import numpy as np
from scipy.ndimage import zoom


'''
 * zmeněí/zvětší 2d obrazek
 *
 *	# zm1 = clipped_zoom(img, 0.5)
 *	# zm2 = clipped_zoom(img, 1.5)
 *
 * 
 * @param image_3d = (depth, width, height) 
 * @param zoom_factor = 0-inf
 * @return image_3d
'''
def cv2_clipped_zoom(img, zoom_factor):
    """
    Center zoom in/out of the given image and returning an enlarged/shrinked view of 
    the image without changing dimensions
    Args:
        img : Image array
        zoom_factor : amount of zoom as a ratio (0 to Inf)
    """
    height, width = img.shape[:2] # It's also the final desired shape
    new_height, new_width = int(height * zoom_factor), int(width * zoom_factor)

    ### Crop only the part that will remain in the result (more efficient)
    # Centered bbox of the final desired size in resized (larger/smaller) image coordinates
    y1, x1 = max(0, new_height - height) // 2, max(0, new_width - width) // 2
    y2, x2 = y1 + height, x1 + width
    bbox = np.array([y1,x1,y2,x2])
    # Map back to original image coordinates
    bbox = (bbox / zoom_factor).astype(np.int)
    y1, x1, y2, x2 = bbox
    cropped_img = img[y1:y2, x1:x2]

    # Handle padding when downscaling
    resize_height, resize_width = min(new_height, height), min(new_width, width)
    pad_height1, pad_width1 = (height - resize_height) // 2, (width - resize_width) //2
    pad_height2, pad_width2 = (height - resize_height) - pad_height1, (width - resize_width) - pad_width1
    pad_spec = [(pad_height1, pad_height2), (pad_width1, pad_width2)] + [(0,0)] * (img.ndim - 2)

    result = cv.resize(cropped_img, (resize_width, resize_height))
    result = np.pad(result, pad_spec, mode='constant')
    assert result.shape[0] == height and result.shape[1] == width
    return result


'''
 * zmeněí/zvětší 3d obrazek
 * 
 * @param image_3d = (depth, width, height) 
 * @param zoom_factor = 0-inf
 * @return image_3d
'''
def image_3d_clipped_zoom(image_3d, zoom_factor):
	# Rotate
	for img in range(0, image_3d.shape[0]):
		image_3d[img] = cv2_clipped_zoom(image_3d[img], zoom_factor)
	return image_3d


'''
 * Otoci 3d obrazek ve tvaru (depth, width, height) o urcity uhel
 * 
 * @param image_3d = (depth, width, height) 
 * @param angle = uhel ve stupnich
 * @return image_3d
'''
def image_3d_rotate(image_3d, rotation_angle):
	# Rotate
	for img in range(0, image_3d.shape[0]):
		image_3d[img] = imutils.rotate(image_3d[img], rotation_angle)
	return image_3d

'''
 * Zmensi/zvetsi 3d obrazek ve tvaru (depth, width, height) o urcitou velikost
 * 
 * @param image_3d = (depth, width, height) 
 * @param resize_factor = zmenseni/zvetseni na skale 0-1 popr. vetsi jak 1 pro zvetseni
 * @param diagonal_shift_index = premistovani zmenseneho obrazku po diagonale, mozne hodnoty: 0.0 - 1.0
 * @return image_3d
'''
def image_3d_resize(image_3d, resize_factor, diagonal_shift_index = 0.5):
	# Rotate
	if resize_factor < 0.1:
		sys.exit("Příliš malá hodnota")

	if diagonal_shift_index > 1.0 or diagonal_shift_index < 0.0:
		sys.exit("parametr: diagonal_shift_index musi byt v rozsahu 0-1")

	new_width = int(image_3d.shape[1]*resize_factor)
	new_height = int(image_3d.shape[2]*resize_factor)

	new_position_x = int((image_3d.shape[1] - new_width) * diagonal_shift_index)
	new_position_y = int((image_3d.shape[2] - new_height) * diagonal_shift_index)

	if new_position_x > 0 and new_position_y > 0:
		new_resized_image = np.zeros(image_3d.shape, dtype=image_3d.dtype)
	else:
		# pokud obrazek bude vetsi nez je original
		new_resized_image = np.zeros((image_3d.shape[0], new_width, new_height), dtype=image_3d.dtype)

	block = np.ndarray(( new_width, new_height), dtype=image_3d.dtype)

	for img in range(0, image_3d.shape[0]):
		block = imutils.resize(image_3d[img], new_width) # smenzeny slice

		if new_position_x > 0 and new_position_y > 0:
			new_resized_image[img][new_position_x:new_position_x+block.shape[0], new_position_y:new_position_y+block.shape[1]] = block
		else:
			new_resized_image[img][0:0+block.shape[0], 0:0+block.shape[1]] = block
	return new_resized_image


def dice_coefficient(y_true, y_pred, smooth=.1):
	"""
	Dice = (2*|X & Y|)/ (|X|+ |Y|)
		 =  2*sum(|A*B|)/(sum(A^2)+sum(B^2))
	ref: https://arxiv.org/pdf/1606.04797v1.pdf
	"""
	y_true = K.flatten(y_true)
	y_pred = K.flatten(y_pred)
	intersection = K.sum(K.abs(y_true * y_pred))
	return (2. * intersection) / (K.sum(K.square(y_true)) + K.sum(K.square(y_pred)) + smooth)


def dice_loss(y_true, y_pred):
	return 1-dice_coefficient(y_true, y_pred)


'''
 * Vraci zpracovane pole 3D obrazku
 * 
 * @image_path = cesta k souboru nii
 * @newshape = jak bude potreba pole reshapnout na jinej tvat
 * @return array
'''
def get_3D_nii_image(image_path, newshape = None, cast = sitk.sitkInt16):
	if not os.path.exists(image_path):
		print("get_3D_nii_image: adresář: "+image_path+" neexistuje")
		sys.exit()
	read = sitk.ReadImage(image_path)
	#print(read.GetPixelIDTypeAsString())
	# kdyz bych dal Uint16, TAK OREZEJE ZAPORNY HDONOTY,a to nechceme!
	if cast:
		read = sitk.Cast( read, cast ) # sitkUInt8
	else:
		read = sitk.Cast( read, sitk.sitkInt16 ) 
		
	img_array = sitk.GetArrayFromImage(read)
	if newshape != None:
		img_array = np.reshape(img_array, newshape)
	return img_array


'''
 * Vraci zpracovane pole 3D obrazku
 * 
 * @image_path = cesta k adresari, kde jsou PNG mozku
 * @newshape = jak bude potreba pole reshapnout na jinej tvat
 * @return array
'''
def get_3D_png_image(image_path_folder, newshape = None):
	if not os.path.exists(image_path_folder):
		print("get_3D_png_image: adresář neexistuje")
		sys.exit()
	images = os.listdir(image_path_folder)
	images.sort()
	images_total = len(images)

	# inicializa numpy pole
	for image in images:
		image_path = os.path.join(image_path_folder, image)
		img_tmp = imread(image_path, as_gray=True)
		width, height = img_tmp.shape
		img_array =  np.ndarray((images_total, width, height), dtype=np.uint8)
		break

	i = 0
	for image in images:
		image_path = os.path.join(image_path_folder  , image)
		img = imread(image_path, as_gray=True)
		img = np.array([img])
		img_array[i] = img
		i += 1

	if newshape != None:
		img_array = np.reshape(img_array, newshape)
	return img_array



'''
 * Prodju slozku, ktera obsahuje podslokzy s png slicy 3d obrazku a udela z nic numpy pole
 * Umoznuje i to, ze pokud kazda slozka ma nejakej prefix, kterej slozky obrazku sdrzuje podle kanalu
 * tak umi podle techto prefixu 3d obrazky nahrat do pole
 * fce umi bud prefiy nebo postfixy
 * 
 * @param src = cesta k adresari, kde jsou PNG mozku
 * @param channel_dir_prefix = prefixy
 * @param channel_dir_postfix = postfixy
 * @param channels = pocet kanalu
 * @param return array
'''
def process_all_3d_png_in_dir_with_channel(src, channel_dir_prefix = [], channel_dir_postfix = [], channels = 3, channels_result = 3):
	if not os.path.exists(src):
		print("adresář neexistuje")
		sys.exit()
	channels_images = None
	for root, subdirs, files in os.walk(src):
		subdirs.sort()
		prefixes_postfixes = None
		if len(channel_dir_prefix) > 0:
			prefixes_postfixes = channel_dir_prefix
		else:
			prefixes_postfixes = channel_dir_postfix

		subdir_index = 0
		for prefix in prefixes_postfixes:
			channel_index = 0
			for subdir in subdirs:
				if channel_index == channels_result:	# timto rikame, aby po zpracovani POCTU KANALU channels_result SKONCIL
					break
				if subdir.startswith(prefix):
					p('Zpracovávám složku: ' + subdir)
					tmp_path = os.path.join(src  , subdir)
					img = get_3D_png_image(tmp_path)
					if channels_images is None:
						channels_images = np.empty((int(len(subdirs)/channels), channels_result, *img.shape))
					
					channels_images[subdir_index][channel_index] = img
					channel_index+=1

			subdir_index+=1

	return channels_images


def split_3channels_3d_images_into_arrays(arrays, channel_position = 'last'):
	if channel_position == 'last':
		arrays = np.moveaxis(arrays, 4,0)
		return arrays[0], arrays[1], arrays[2]
	else:
		return arrays[0], arrays[1], arrays[2]


'''
 * Vraci zpracovane pole 3D obrazku
 * 
 * @filename = cesta k souboru nii
 * @return array (Image, Origin, Spacing)
'''
def get_3D_nii_image_full(filename):
	if not os.path.exists(filename):
		print("get_3D_nii_image_full: adresář: "+filename+" neexistuje")
		sys.exit()
	itkimage = sitk.ReadImage(filename)
	Image = sitk.GetArrayFromImage(itkimage)
	Origin = np.array(list(itkimage.GetOrigin()))
	Spacing = np.array(list(itkimage.GetSpacing()))
	return Image, Origin, Spacing


'''
 * Ulozi pole 3D obrazku s mezerou mezi slicy
 * 
 * @param image = numpy array image
 * @param origin = origin
 * @param spacing = spacing
 * @param filename = cesta k souboru nii
 * @return array (Image, Origin, Spacing)
'''
def save_3D_nii_image_with_spacing(image, origin, spacing, filename):
	itkimage = sitk.GetImageFromArray(image, isVector=False)
	itkimage.SetSpacing(spacing)
	itkimage.SetOrigin(origin)
	sitk.WriteImage(itkimage, filename, True)
	return True


'''
 * Ulozi pole 3D obrazku
 * 
 * @param img = numpy array image, obrazek ve tvaru: (pocet slicu, sirka, vyska) tj. (48, 240, 240)
 * @param dest_path = cesta kam ulozit tj. vcetne jmena souboru .nii.gz napr.:  dest_path = os.path.join(os.getcwd() + '/pre/FLAIR.nii.gz'))
 * @return bool
'''
def save_3D_nii_image(img, dest_path, norm = True):
	dirname = os.path.dirname(dest_path)

	if not os.path.exists(dirname):
		os.makedirs(dirname)

	if not os.path.exists(dirname):
		print("save_3D_nii_image: adresář " + dirname +"neexistuje")
		sys.exit()

	if norm:
		img = normalization_3d(img)
	im = sitk.GetImageFromArray(img, isVector=False)
	sitk.WriteImage(im, dest_path)
	return True


'''
 * Vraci normalizovany slice 2D/3D obrazku
 * 
 * @image_2d = obrazek ve tvaru: (sirka, vyska) tj. (240, 240)
 * @min_value = min hodnota obrazku, kterou muze nabyvat ve stupni sedi, 0 = cerna, 255 = bila
 * @max_value = max hodnota obrazku, kterou muze nabyvat ve stupni sedi, 0 = cerna, 255 = bila
 * @type = výsledný typ slicu
 * @return image
'''
def normalization(image_2d, min_value=0, max_value=255, type='uint8', histeq = False):
	if len(image_2d.shape) != 2:
		sys.exit("Spatna dimenze obrazku pro normalizaci")

	img_slice = image_2d

	img_slice_min = img_slice.min()
	img_slice_max = img_slice.max()
	if img_slice_min >= 0:
		img_slice -= img_slice_min
	if img_slice_min <= min_value:
		img_slice += (img_slice_min * (-1))
	#print("slice min before: "+str(img_slice_min) + " | slice min after: " + str(img_slice.min()) + " | slice max before: " + str(img_slice_max) + " | slice max after: " + str(img_slice.max()))
	img_slice = ((img_slice / img_slice.max())*max_value).astype(type)

	# histogram equalization
	img_slice=cv.equalizeHist(img_slice) if histeq else img_slice 

	return img_slice


'''
 * Vraci normalizovany slice 2D/3D obrazku
 * 
 * @param image_3d = obrazek ve tvaru: (depth, sirka, vyska) tj. (48, 240, 240)
 * @param min_value = min hodnota obrazku, kterou muze nabyvat ve stupni sedi, 0 = cerna, 255 = bila
 * @param max_value = max hodnota obrazku, kterou muze nabyvat ve stupni sedi, 0 = cerna, 255 = bila
 * @param type = výsledný typ slicu
 * @return image
'''
def normalization_3d(image_3d, min_value=0, max_value=255, type='uint8', histeq = False):
	if len(image_3d.shape) != 3:
		sys.exit("Spatna dimenze obrazku pro normalizaci")

	result_image_3d = np.ndarray(image_3d.shape)
	for index in range(0, image_3d.shape[0]):
		img_slice = image_3d[index]
		img_slice = normalization(img_slice, min_value, max_value, type, histeq)
		result_image_3d[index] = img_slice

	return result_image_3d


'''
 * Vraci zpracovane pole 3D obrazku
 * 
 * @param img = obrazek ve tvaru: (pocet slicu, sirka, vyska) tj. (48, 240, 240)
 * @param dest_path_folder = slozka kam PNG obrazky ulozit napr.: dest_path_folder = os.path.join(os.getcwd() + '/14')
 * @param norm = bude se provadet normalizace
 * @return bool
'''
def save_3D_png_image(img, dest_path_folder, norm = True):
	if not os.path.exists(dest_path_folder):
		os.makedirs(dest_path_folder)

	if not os.path.exists(dest_path_folder):
		print("save_3D_png_image: adresář neexistuje")
		sys.exit()

	image_slices, width, height = img.shape

	# pruchod
	for image_slice in range(0, image_slices):
		image_path = os.path.join(dest_path_folder, "{:03}.png".format(image_slice) )
		img_slice = img[image_slice]
		if norm:
			img_slice = normalization(img_slice)
		imsave(image_path, img_slice)
	return True


'''
 * Vraci zpracovane pole 3D obrazku a provede histogram equalization
 * 
 * @param img = obrazek ve tvaru: (pocet slicu, sirka, vyska) tj. (48, 240, 240)
 * @param dest_path_folder = slozka kam PNG obrazky ulozit napr.: dest_path_folder = os.path.join(os.getcwd() + '/14')
 * @param norm = bude se provadet normalizace
 * @return bool
'''
def save_3D_png_image_histeq(img, dest_path_folder):
	if not os.path.exists(dest_path_folder):
		os.makedirs(dest_path_folder)

	if not os.path.exists(dest_path_folder):
		print("adresář neexistuje")
		sys.exit()

	image_slices, width, height = img.shape

	# pruchod
	for image_slice in range(0, image_slices):
		image_path = os.path.join(dest_path_folder, "{:03}.png".format(image_slice) )
		img_slice = img[image_slice]
		img_slice = normalization(img_slice, 0, 255, 'uint8', True)
		imsave(image_path, img_slice)
	return True


'''
 * Stopne program
 * 
 * @param arg = numpy array image
 * @return void
'''
def d(arg):
	sys.exit(str(arg))


'''
 * Vypise hlasku
 * 
 * @param arg = numpy array image
 * @return void
'''
def p(arg):
	print(arg)


'''
 * Vytvorří tridy u masky obrazku
 * vstup musi byt obrazek X*Y a ne cely obrazek X*Y*Z
 * 
 * @param width
 * @param height
 * @param mask
 * @param num_class
 * @return array
'''
def binarylabel(width, height, mask, num_class):
	x = np.zeros([width, height, num_class])
	types = [] 
	for i in range(width):
		for j in range(height):
			if (int(mask[i][j]) >= num_class):
				d("Houstne mame problem, velikost labelu je vetsi nez je povoley indexovani, pocet trid:" +str(num_class)+"; label:" + str(mask[i][j]))
			x[i, j, int(mask[i][j])] = 1
			if int(mask[i][j]) not in types:
				types.append(int(mask[i][j]))
	#print(types)
	return x



'''
 * Vytvorří tridy u masky obrazku
 * vstup musi byt obrazek X*Y a ne cely obrazek X*Y*Z
 * 
 * @param depth
 * @param width
 * @param height
 * @param mask
 * @param num_class
 * @return array
'''
def binarylabel3D(depth, width, height, mask, num_class):
	x = np.zeros([depth, width, height, num_class], dtype=np.uint8)
	for d in range(depth):
		for i in range(width):
			for j in range(height):
				if (int(mask[d][i][j]) >= num_class):
					d("Houstne mame problem, velikost labelu je vetsi nez je povoley indexovani, pocet trid:" +str(num_class)+"; label:" + str(mask[i][j]))
				x[d, i, j, int(mask[d][i][j])] = 1

	return x


'''
 * REVERZNI FUNKCE PRO binarylabel
 * 
 * @param width = width
 * @param height = height
 * @param mask = mask
 * @return mask
'''
def binarylabelToBack( width, height, mask):
	mask = (mask[:, :, :] * 255.).astype(np.uint8)
	x = np.zeros([width, height], dtype=np.uint8)
	for i in range(width):
		for j in range(height):
			# x[i, j] = np.amax(mask[i][j])
			#mm = np.squeeze(mask, axis=3) 
			#maxkey = (np.where(mask[i][j]==mask[i][j].max())) # nactu index nejvyssi polozky

			maxkey = np.argmax(mask[i,j,:])
			x[i, j] =	maxkey					# ulozim cislo masky
	return x




'''
 * Vymaze pozadi u predikovanej obrazku, napr vznikly sum na zaklade neprenosti apod.
 * 
 * @param predicted_3d_image = (depth, width, height)
 * @param mask_3d_image =  = (depth, width, height)
 * @return corrected predicted 3d image
'''
def remove_background_by_mask(predicted_3d_image, mask_3d_image):
	depth = predicted_3d_image.shape[0] 
	width = predicted_3d_image.shape[1] 
	height = predicted_3d_image.shape[2] 
	for d in range(depth):
		for w in range(width):
			for h in range(height):
				if mask_3d_image[d,w,h]==0:
					predicted_3d_image[d,w,h] = 0
	return predicted_3d_image


'''
 * REVERZNI FUNKCE PRO binarylabel ve 3D
 * 
 * @param depth = depth
 * @param width = width
 * @param height = height
 * @param mask = mask
 * @return mask
'''
def binarylabelToBack3D(depth, width, height, mask):
	x = np.zeros([depth, width, height], dtype=np.uint8)
	for d in range(depth):
		for i in range(width):
			for j in range(height):
				maxkey = np.argmax(mask[d,i,j,:])
				x[d,i, j] =	maxkey					# ulozim cislo masky
	return x


'''
 * Dokaze extrahovat 3D obrazek na mensi patche
 * 
 * @volume = obrazek ve 3D tj. (depth, height, width)
 * @patch_shape = jakou ma mit patch velikost ve formatu: (depth, height, width)
 * @extraction_step = krok (depth, height, width)
 * @return patches
'''
def extract_patches(volume, patch_shape, extraction_step) :
	patches = sk_extract_patches(
		volume,
		patch_shape=patch_shape,
		extraction_step=extraction_step)

	ndim = len(volume.shape)
	npatches = np.prod(patches.shape[:ndim])
	#return patches.reshape([-1] + list(patch_shape))
	return patches.reshape((npatches, ) + patch_shape)


'''
 * Dokaze extrahovat 3D obrazek na mensi patche s překryvem
 * 
 * @image = obrazek ve 3D tj. (depth, height, width)
 * @window_shape = jakou ma mit patch velikost ve formatu: (depth, height, width)
 * @stride_shape = (depth, height, width) => krok o kolik se posune (pokud bude krok mensi nez shape patche, tak tam bude prekryv) 
 * @return patches
'''
def extract_sliding_window_patches(image, window_shape, stride_shape):
	sliding_window = view_as_windows(image , window_shape, stride_shape)
	sliding_window = sliding_window.reshape(sliding_window.shape[0] * sliding_window.shape[1] * sliding_window.shape[2], *window_shape)
	return sliding_window


'''
 * Vynasobi prvky n-tice (x,y,z,d) mezi sebou tj. x*y*z*d
 * 
 * @param tuple
 * @return multiplyed tuple
'''
def tuple_multiply(tuple) :
	num_items = len(tuple)
	ret = 1
	for index in range(0, num_items):
		ret*=tuple[index]
	return ret



'''
 * Dokaze projit 3d obrazek ktery je rozlozen do patchu s 50% prekryvem a slozit obraek zpet bez prekryvu
 * dokaze resit jen 50% prekryv
 *
 * @param image = (patches, depth, width, height) napr.: (128, 24, 30 ,30) z obrazku: (48, 240, 240)
 * @param patch_shape = (depth, width, height)
 * @param stride_shape =  velikosti 3d kroku (50% of patch shape, 50% of patch shape, 50% of patch shape)
 * @param original_shape = (depth, width, height)
'''
def create_blocks_from_sliding_window_patches(  image,  patch_shape, stride_shape, original_shape):
	
	stride_shape_test = [int(x/2) for x in patch_shape]
	#if stride_shape != stride_shape_test:
		#sys.exit("prekryv je definovan spatne!, musi byt 50%")

	sliding_window = view_as_windows(np.zeros(original_shape) , patch_shape, stride_shape)

	depth_scale  = sliding_window.shape[0]
	width_scale  = sliding_window.shape[1]
	height_scale = sliding_window.shape[2]

	if len(image.shape)!=6:
		image = image.reshape((depth_scale, width_scale, height_scale, *patch_shape))

	if len(image.shape)!=6:
		sys.exit("spatny shape 3D obrazku!")

	result_d_dim = int(depth_scale / 2) +1 if depth_scale%2!=0 else  int(depth_scale / 2) 
	result_w_dim = int(width_scale / 2) +1 if width_scale%2!=0 else  int(width_scale / 2) 
	result_h_dim = int(height_scale / 2) +1 if height_scale%2!=0 else  int(height_scale / 2) 
	ret_array = np.ndarray((result_d_dim, result_w_dim, result_h_dim, *patch_shape), dtype=np.uint8)

	ii = 0
	for i in range(0, depth_scale):
		if (i+1)%2!=0:
			wi = 0
			for w in range(0, width_scale):
				if (w+1)%2!=0:
					hi = 0
					for h in range(0, height_scale):
						if (h+1)%2!=0:		# tohle je jen pro overlap 50% a ne pro jiny!
							ret_array[ii][wi][hi] = image[i][w][h] ## protoze maji stejnou sirku a vysku
							#p(str(i) +" "+ str(w) +" "+ str(h) +" "+ str(wi) +" "+ str(hi)   )
							hi = hi +1
					wi = wi +1
			ii = ii +1
	#d(ret_array.shape)
	ret_array = ret_array.reshape((result_d_dim * result_w_dim * result_h_dim, *patch_shape) )
	return ret_array


'''
 * Zasadi patch do originalni velikosti mozku
 * 
 *
 * @param image_pathes = (patches, depth, width, height) napr.: (128, 24, 30 ,30) , (48, 240, 240)
 * @param patch_shape =  velikost patche (depth, width, height)
 * @param stride_shape = velikost kroku (depth, width, height)
 * @param orig_img_shape = (depth, width, height)
'''
def make_orig_shape_patches(image_pathes, patch_shape, stride_shape, orig_img_shape):

	patch_shape = (image_pathes.shape[1], image_pathes.shape[2], image_pathes.shape[3])

	depth_scale  = int(orig_img_shape[0] / patch_shape[0])
	width_scale  = int(orig_img_shape[1] / patch_shape[1])
	height_scale = int(orig_img_shape[2] / patch_shape[2])

	num_of_patches = image_pathes.shape[0]
	patches_per_depth_level = int(num_of_patches / depth_scale)

	ret_big_array = np.zeros((num_of_patches, *orig_img_shape), dtype=image_pathes.dtype)

	#for depth in range(depth_scale):
	for patch in range(0, num_of_patches):
		tmp_patch =   image_pathes[  patch] 
		ret_array = np.zeros((num_of_patches, *patch_shape), dtype=image_pathes.dtype)
		ret_array[patch]  = tmp_patch
		builded_image = build_image_from_patches(ret_array, (48,240,240))
		ret_big_array[patch] = builded_image

		#save_3D_nii_image(builded_image, os.path.join(os.getcwd() + '/builded_image/build'+str(patch)+'.nii.gz'))
		#d("koncim")
	

	return ret_big_array



'''
 * Slozi obrazek s patchu
 * podmin: vsechny dimenze orig obrazku musi byt delitelne dimenzi patche
 *
 * @param image_3d_patches = (patches, depth, width, height) napr.: (128, 24, 30 ,30) , (48, 240, 240)
 * @param original_shape = (depth, width, height)
'''
def build_image_from_patches(image_3d_patches, original_shape) :
	if len(image_3d_patches.shape) != 4:
		print("Spatny tvar vstupniho obrazku")
		return False
	
	if original_shape[0] % image_3d_patches.shape[1] != 0:
		 print("Spatny pomer dimenze depth!")
		 return False
	if original_shape[1] % image_3d_patches.shape[2] != 0:
		 print("Spatny pomer dimenze width!")
		 return False
	if original_shape[2] % image_3d_patches.shape[3] != 0:
		 print("Spatny pomer dimenze height!")
		 return False

	depth_scale  = int(original_shape[0] / image_3d_patches.shape[1])
	width_scale  = int(original_shape[1] / image_3d_patches.shape[2])
	height_scale = int(original_shape[2] / image_3d_patches.shape[3])

	patch_depth = image_3d_patches.shape[1]
	patch_width = image_3d_patches.shape[2]
	patch_height = image_3d_patches.shape[3]

	image_3d_patches = image_3d_patches.reshape((depth_scale, width_scale, height_scale, patch_depth, patch_width, patch_height ))
	image_3d_patches = np.moveaxis(image_3d_patches, 3, 1)

	# priklad:
	# (128,24,30,30) -> (2,8,8,  24,30,30)
	# (2,8,8, 24,30,30) -> (2,24,8,8,30,30)
	cube_parts = depth_scale
	cube_x_pathes = width_scale
	cube_y_pathes = height_scale
	slices = patch_depth
	ret_array = np.ndarray(original_shape, dtype=np.uint8)
	
	inde_nii = 0
	for cube_part in range(0, cube_parts):
		for slice in range(0, slices):
			 # zde by meli byt jednotlie radky, ktere se pak vzajemne musi zkonkatenovat
			tmp_patch_col = None
			for cube_x_path in range(0, cube_x_pathes):
				# vytvoreni radku
				tmp_patch_row = image_3d_patches[cube_part][slice][cube_x_path][0]
				for cube_y_path in range(1, cube_y_pathes):
					row_path = image_3d_patches[cube_part][slice][cube_x_path][cube_y_path]
					tmp_patch_row = np.concatenate((tmp_patch_row, row_path), axis=1)
				# vytvoreni sloupce
				if tmp_patch_col is None: # init
					tmp_patch_col = tmp_patch_row
				else:
					tmp_patch_col = np.concatenate((tmp_patch_col, tmp_patch_row), axis=0)
			# pridani slicu do pole sliců
			ret_array[inde_nii] = tmp_patch_col
			inde_nii = inde_nii + 1
	return ret_array
				

'''
 * Slozi obrazek z nezarovannych patchu
 * podmin: vsechny dimenze orig obrazku musi byt delitelne dimenzi patche
 *
 * @param image_3d_patches = (patches, depth, width, height) napr.: (128, 24, 30 ,30) , (48, 240, 240)
 * @param original_shape = (depth, width, height)
'''
def build_image_from_unpadded_patches(image_3d_patches, original_shape) :
	if len(image_3d_patches.shape) != 4:
		print("Spatny tvar vstupniho obrazku")
		return False

	depth_scale  = int(original_shape[0] / image_3d_patches.shape[1])
	width_scale  = int(original_shape[1] / image_3d_patches.shape[2])
	height_scale = int(original_shape[2] / image_3d_patches.shape[3])

	patch_depth = image_3d_patches.shape[1]
	patch_width = image_3d_patches.shape[2]
	patch_height = image_3d_patches.shape[3]

	image_3d_patches = image_3d_patches.reshape((depth_scale, width_scale, height_scale, patch_depth, patch_width, patch_height ))
	image_3d_patches = np.moveaxis(image_3d_patches, 3, 1)

	# priklad:
	# (128,24,30,30) -> (2,8,8,  24,30,30)
	# (2,8,8, 24,30,30) -> (2,24,8,8,30,30)
	cube_parts = depth_scale
	cube_x_pathes = width_scale
	cube_y_pathes = height_scale
	slices = patch_depth
	ret_array = None
	
	inde_nii = 0
	for cube_part in range(0, cube_parts):
		for slice in range(0, slices):
			 # zde by meli byt jednotlie radky, ktere se pak vzajemne musi zkonkatenovat
			tmp_patch_col = None
			for cube_x_path in range(0, cube_x_pathes):
				# vytvoreni radku
				tmp_patch_row = image_3d_patches[cube_part][slice][cube_x_path][0]
				for cube_y_path in range(1, cube_y_pathes):
					row_path = image_3d_patches[cube_part][slice][cube_x_path][cube_y_path]
					tmp_patch_row = np.concatenate((tmp_patch_row, row_path), axis=1)
				# vytvoreni sloupce
				if tmp_patch_col is None: # init
					tmp_patch_col = tmp_patch_row
				else:
					tmp_patch_col = np.concatenate((tmp_patch_col, tmp_patch_row), axis=0)
			# pridani slicu do pole sliců
			if ret_array is None:
				ret_array = np.ndarray((original_shape[0], *tmp_patch_col.shape), dtype=np.uint8)

			ret_array[inde_nii] = tmp_patch_col
			inde_nii = inde_nii + 1
	return ret_array
				



'''
 * Slozi obrazek s patchu
 *
 * @param image_3d_patches = (patches, depth, width, height, classes)
 * @param original_shape = (depth, width, height)
'''
def build_mask_from_patches(mask_3d_patches, original_shape) :
	if len(mask_3d_patches.shape) != 5:
		sys.exit("Spatny tvar vstupniho obrazku  masky")
	return patches.reshape((npatches, ) + patch_shape)


def findfiles(dirname, pattern):
	cwd = os.getcwd()
	if dirname:
		os.chdir(dirname)
 
	result = []
	for filename in glob.iglob(pattern):
		result.append(filename)
	os.chdir(cwd)
	return result


'''
	def get_3D_nii_image(image_path, newshape = None):
	def get_3D_png_image(image_path_folder, newshape = None):
	def get_3D_nii_image_full(filename):
	def save_3D_nii_image_with_spacing(image, origin, spacing, filename):
	def save_3D_nii_image(img, dest_path):
	def save_3D_png_image(img, dest_path_folder):
'''


#if __name__ == '__main__':
	#main()
	#pass