master 69169d86126e cached
34 files
72.4 KB
19.9k tokens
58 symbols
1 requests
Download .txt
Repository: ugent-korea/pytorch-unet-segmentation
Branch: master
Commit: 69169d86126e
Files: 34
Total size: 72.4 KB

Directory structure:
gitextract_h5owzdln/

├── .gitignore
├── LICENSE
├── README.md
├── readme_images/
│   ├── bright_10
│   ├── c_lb
│   ├── c_lt
│   ├── c_rb
│   ├── c_rt
│   ├── description
│   ├── division_matrix
│   ├── elastic_1
│   ├── file_name_description
│   ├── final_concate
│   ├── flip_both
│   ├── flip_hori
│   ├── flip_vert
│   ├── gn_10
│   ├── gn_100
│   ├── gn_50
│   ├── original_image
│   ├── un_100
│   ├── un_50
│   └── uniform_10
└── src/
    ├── accuracy.py
    ├── advanced_model.py
    ├── dataset.py
    ├── main.py
    ├── mean_std.py
    ├── modules.py
    ├── post_processing.py
    ├── pre_processing.py
    ├── result_visualization.py
    ├── save_history.py
    └── simple_model.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*.csv
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 UGent Korea

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# pytorch-unet-segmentation

**Members** : <a href="https://github.com/PyeongKim">PyeongEun Kim</a>, <a href="https://github.com/juhlee">JuHyung Lee</a>, <a href="https://github.com/mijeongl"> MiJeong Lee </a>

**Supervisors** : <a href="https://github.com/utkuozbulak">Utku Ozbulak</a>, Wesley De Neve

## Description

This project aims to implement biomedical image segmentation with the use of U-Net model. The below image briefly explains the output we want:

<p align="center">
<img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/segmentation_image.jpg">


The dataset we used is Transmission Electron Microscopy (ssTEM) data set of the Drosophila first instar larva ventral nerve cord (VNC), which is dowloaded from [ISBI Challenge: Segmentation of of neural structures in EM stacks](http://brainiac2.mit.edu/isbi_challenge/home)

The dataset contains 30 images (.png) of size 512x512 for each train, train-labels and test.


## Table of Content

* [Dataset](#dataset)

* [Preprocessing](#preprocessing)

* [Model](#model)

* [Loss function](#lossfunction)

* [Post-processing](#postprocessing)

* [Results](#results)

* [Dependency](#dependency)

* [References](#references)



## Dataset <a name="dataset"></a>

```ruby
class SEMDataTrain(Dataset):

    def __init__(self, image_path, mask_path, in_size=572, out_size=388):
        """
        Args:
            image_path (str): the path where the image is located
            mask_path (str): the path where the mask is located
            option (str): decide which dataset to import
        """
        # All file names
	# Lists of image path and list of labels
        # Calculate len
        # Calculate mean and stdev

    def __getitem__(self, index):
        """Get specific data corresponding to the index
        Args:
            index (int): index of the data

        Returns:
            Tensor: specific data on index which is converted to Tensor
        """
        """
        # GET IMAGE
        """
        #Augmentation on image
          # Flip 
          # Gaussian_noise
          # Uniform_noise
          # Brightness
          # Elastic distort {0: distort, 1:no distort}
          # Crop the image
          # Pad the image
          # Sanity Check for Cropped image
          # Normalize the image

          # Add additional dimension
          # Convert numpy array to tensor
        
        #Augmentation on mask
          # Flip same way with image
          # Elastic distort same way with image
          # Crop the same part that was cropped on image
          # Sanity Check
          # Normalize the mask to 0 and 1
      
        # Add additional dimension
        # Convert numpy array to tensor

        return (img_as_tensor, msk_as_tensor)

    def __len__(self):
        """
        Returns:
            length (int): length of the data
        """

```

## Preprocessing <a name="preprocessing"></a>

We preprocessed the images for data augmentation. Following preprocessing are :
   * Flip
   * Gaussian noise
   * Uniform noise
   * Brightness
   * Elastic deformation
   * Crop
   * Pad 
   
#### Image Augmentation


<p align="center">
  <img width="250" height="250" src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/original.png"> <br />Original Image</td>
</p>


<table border=0 width="99%" >
	<tbody> 
    <tr>		<td width="99%" align="center" colspan="4"><strong>Image</td>
		</tr>
		<tr>
			<td width="19%" align="center"> Flip  </td> 
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/flip_vert"> <br />Vertical  </td> 
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/flip_hori">  <br />Horizontal</td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/flip_both"> <br />Both</td>
		</tr>
      		</tr>
		<tr>
			<td width="19%" align="center"> Gaussian noise </td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/gn_10"> <br />Standard Deviation: 10</td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/gn_50"> <br />Standard Deviation: 50</td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/gn_100"> <br />Standard Deviation: 100</td>
   		</tr>
		<tr>
			<td width="19%" align="center"> Uniform noise </td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/uniform_10"> <br />Intensity: 10 </td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/un_50"> <br />Intensity: 50</td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/un_100"> <br />Intensity: 100</td>
		</tr>
      		</tr>
		<tr>
			<td width="19%" align="center"> Brightness </td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/bright_10"> <br />Intensity: 10</td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/br_50.png"> <br />Intensity: 20</td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/br_100.png"> <br />Intensity: 30</td>
		</tr>
      		</tr>
		<tr>
			<td width="19%" align="center"> Elastic deformation </td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/ed_10.png"> <br />Random Deformation: 1</td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/ed_34.png"> <br />Random Deformation: 2</td>
			<td width="27%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/ed_50.png"> <br />Random Deformation: 3</td>
		</tr>
		</tr>
	</tbody>
</table>       

#### Crop and Pad

<table border=0 width="99%" >
	<tbody> 
    <tr>		<td width="99%" align="center" colspan="4"><strong>Crop</td>
	    </tr>
		<tr>
			<td width="25%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/c_lb"> <br />  Left Bottom </td>
			<td width="25%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/c_lt"> <br /> Left Top</td> 
			<td width="25%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/c_rb"> <br /> Right Bottom</td>
			<td width="25%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/c_rt"> <br /> Right Top</td> 
		</tr>
      		</tr>
	</tbody>
</table>         

Padding process is compulsory after the cropping process as the image has to fit the input size of the U-Net model. 

In terms of the padding method, **symmetric padding** was done in which the pad is the reflection of the vector mirrored along the edge of the array. We selected the symmetric padding over several other padding options because it reduces the loss the most. 

To help with observation, a ![#ffff00](https://placehold.it/15/ffff00/000000?text=+) 'yellow border' is added around the original image: outside the border indicates symmetric padding whereas inside indicates the original image.

<table border=0 width="99%" >
	<tbody> 
    <tr>		<td width="99%" align="center" colspan="4"><strong>Pad</td>
	    </tr>
		<tr>
			<td width="25%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/p_lb.PNG"> <br />  Left Bottom </td>
			<td width="25%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/p_lt.PNG"> <br /> Left Top</td> 
			<td width="25%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/p_rb.PNG"> <br /> Right bottom</td>
			<td width="25%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/p_rt.PNG"> <br /> Right Top</td> 
		</tr>
      		</tr>
	</tbody>
</table>         


## Model <a name="model"></a>

#### Architecture

We have same structure as U-Net Model architecture but we made a small modification to make the model smaller.

![image](https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/UNet_custom_parameter.png)

## Loss function <a name="lossfunction"></a>

We used a loss function where pixel-wise softmax is combined with cross entropy.

#### Softmax
![image](https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/softmax(1).png)

#### Cross entropy
![image](https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/cross%20entropy(1).png)

## Post-processing <a name="postprocessing"></a>
In attempt of reducing the loss, we did a post-processing on the prediction results. We applied the concept of watershed segmentation in order to point out the certain foreground regions and remove regions in the prediction image which seem to be noises.

![postprocessing](https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/postprocess.png)

The numbered images in the figure above indicates the stpes we took in the post-processing. To name those steps in slightly more detail:

	* 1. Convertion into grayscale
	* 2. Conversion into binary image
	* 3. Morphological transformation: Closing
	* 4. Determination of the certain background
	* 5. Calculation of the distance
	* 6. Determination of the certain foreground
	* 7. Determination of the unknown region
	* 8. Application of watershed
	* 9. Determination of the final result

### Conversion into grayscale 

The first step is there just in case the input image has more than 1 color channel (e.g. RGB image has 3 channels) 

### Conversion into binary image

Convert the gray-scale image into binary image by processing the image with a threshold value: pixels equal to or lower than 127 will be pushed down to 0 and greater will be pushed up to 255. Such process is compulsory as later transformation processes takes in binary images.

### Morphological transformation: Closing.

We used **morphologyEX()** function in cv2 module which removes black noises (background) within white regions (foreground).
	
### Determination of the certain background

We used **dilate()** function in cv2 module which emphasizes/increases the white region (foreground). By doing so, we connect detached white regions together - for example, connecting detached cell membranes together - to make ensure the background region.

### Caculation of the distance

This step labels the foreground with a color code: ![#ff0000](https://placehold.it/15/ff0000/000000?text=+) red color indicates farthest from the background while ![#003bff](https://placehold.it/15/003bff/000000?text=+) blue color indicates closest to the background.

### Determination of the foreground

Now that we have an idea of how far the foreground is from the background, we apply a threshold value to decide which part could surely be the foreground.

The threshold value is the maximum distance (calculated from the previous step) multiplied by a hyper-parameter that we have to manually tune. The greater the hyper-parameter value, the greater the threshold value, and therefore we will get less area of certain foreground. 

### Determination of the unknown region

From previous steps, we determined sure foreground and background regions. The rest will be classified as *'unknown'* regions.

### Label the foreground: markers

We applied **connectedComponents()** function from the cv2 module on the foreground to label the foreground regions with color to distinguish different foreground objects. We named it as a 'marker'.

### Application of watershed and Determination of the final result

After applying **watershed()** function from cv2 module on the marker, we obtained an array of -1, 1, and many others. 

	* -1 = Border region that distinguishes foreground and background
	*  1 = Background region

To see the result, we created a clean white page of the same size with the input image. then we copied all the values from the watershed result to the white page except 1, which means that we excluded the background.

## Results <a name="results"></a>

<table style="width:99%">
	<tr> 
		<th>Optimizer</th>
	    	<th>Learning Rate</th>
	    	<th>Lowest Loss</th>
	    	<th>Epoch</th>
		<th>Highest Accuracy</th>
	    	<th>Epoch</th>
	</tr>
	<tr>
		<th rowspan="3">SGD</th>
		<td align="center">0.001</td>
		<td align="center">0.196972</td>
		<td align="center">1445</td>
		<td align="center">0.921032</td>
		<td align="center">1855</td>
	</tr>
	<tr>
		<td align="center">0.005</td>
		<td align="center">0.205802</td>
		<td align="center">1815</td>
		<td align="center">0.918425</td>
		<td align="center">1795</td>
	</tr>
	<tr>
		<td align="center">0.01</td>
		<td align="center">0.193328</td>
		<td align="center">450</td>
		<td align="center">0.922908</td>
		<td align="center">450</td>
	</tr>
	<tr>
		<th rowspan="3">RMS_prop</th>
		<td align="center">0.0001</td>
		<td align="center">0.203431</td>
		<td align="center">185</td>
		<td align="center">0.924543</td>
		<td align="center">230</td>
	</tr>
	<tr>
		<td align="center">0.0002</td>
		<td align="center">0.193456</td>
		<td align="center">270</td>
		<td align="center">0.926245</td>
		<td align="center">500</td>
	</tr>
	<tr>
		<td align="center">0.001</td>
		<td align="center">0.268246</td>
		<td align="center">1655</td>
		<td align="center">0.882229</td>
		<td align="center">1915</td>
	</tr>
	<tr>
		<th rowspan="3">Adam</th>
		<td align="center">0.0001</td>
		<td align="center">0.194180</td>
		<td align="center">140</td>
		<td align="center">0.924470</td>
		<td align="center">300</td>
	</tr>
	<tr>
		<td align="center">0.0005</td>
		<td align="center">0.185212</td>
		<td align="center">135</td>
		<td align="center">0.925519</td>
		<td align="center">135</td>
	</tr>
	<tr>
		<td align="center">0.001</td>
		<td align="center">0.222277</td>
		<td align="center">165</td>
		<td align="center">0.912364</td>
		<td align="center">180</td>
	</tr>
		
</table>       


We chose the best learning rate that fits the optimizer based on **how fast the model converges to the lowest error**. In other word, the learning rate should make model to reach optimal solution in shortest epoch repeated. However, the intersting fact was that the epochs of lowest loss and highest accuracy were not corresponding. This might be due to the nature of loss function (Loss function is log scale, thus an extreme deviation might occur). For example, if the softmax probability of one pixel is 0.001, then the -log(0.001) would be 1000 which is a huge value that contributes to loss.
For consistency, we chose to focus on accuracy as our criterion of correctness of model. 



<table border=0 width="99%" >
	<tbody> 
    <tr>		<td width="99%" align="center" colspan="3"><strong>Accuracy and Loss Graph</td>
	    </tr>
		<tr>
			<td width="33%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/SGD_graph.png"> </td> 
			<td width="33%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/RMS_graph.png"> </td>
			<td width="33%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/Adam_graph.png"> </td>
		</tr>
		<tr>
			<td align="center">SGD<br />(lr=0.01,momentum=0.99)</td>
			<td align="center">RMS prop<br />(lr=0.0002)</td>
			<td align="center">Adam<br />(lr=0.0005)</td>
      		</tr>
	</tbody>
</table>       
We used two different optimizers (SGD, RMS PROP, and Adam). In case of SGD the momentum is manually set (0.99) whereas in case of other optimizers (RMS Prop and Adam) it is calculated automatically. 

### Model Downloads

Model trained with SGD can be downloaded via **dropbox**:
https://www.dropbox.com/s/ge9654nhgv1namr/model_epoch_2290.pwf?dl=0


Model trained with RMS prop can be downloaded via **dropbox**:
https://www.dropbox.com/s/cdwltzhbs3tiiwb/model_epoch_440.pwf?dl=0


Model trained with Adam can be downloaded via **dropbox**:
https://www.dropbox.com/s/tpch6u41jrdgswk/model_epoch_100.pwf?dl=0




### Example

<p align="center">
  <img width="250" height="250" src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/validation_img.png"> <br /> Input Image</td>
</p>

<table border=0 width="99%" >
	<tbody> 
    <tr>		<td width="99%" align="center" colspan="5"><strong>Results comparsion</td>
	    </tr>
		<tr>
			<td width="24%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/validation_mask.png"> </td>
			<td width="24%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/validation_RMS.png"> </td>
			<td width="24%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/validation_SGD.png"></td> 
			<td width="24%" align="center"> <img src="https://github.com/ugent-korea/pytorch-unet-segmentation/blob/master/readme_images/validation_Adam.png"> </td>
		</tr>
		<tr>
			<td align="center">original image mask</td>
			<td align="center">RMS prop optimizer <br />(Accuracy 92.48 %)</td>
			<td align="center">SGD optimizer <br />(Accuracy 91.52 %)</td>
			<td align="center">Adam optimizer <br />(Accuracy 92.55 %)</td>
      		</tr>
	</tbody>
</table>       

## Dependency <a name="dependency"></a>

Following modules are used in the project:

    * python >= 3.6
    * numpy >= 1.14.5
    * torch >= 0.4.0
    * PIL >= 5.2.0
    * scipy >= 1.1.0
    * matplotlib >= 2.2.2
   

## References <a name="references"></a> :

[1] O. Ronneberger, P. Fischer, and T. Brox. U-Net: Convolutional Networks for Biomedical Image Segmentation, http://arxiv.org/pdf/1505.04597.pdf

[2] P.Y. Simard, D. Steinkraus, J.C. Platt. Best Practices for Convolutional Neural Networks Applied to Visual Document Analysis, http://cognitivemedium.com/assets/rmnist/Simard.pdf


================================================
FILE: readme_images/description
================================================
z_original: original image
bright_x: brightness increased by x
elastic_x: different elastic 
flip_x: flip on x way
gaus_x: gaussian noise added with mean of 0 and std of x
uniform_x: uniform noise added with lower bound of -x and upper bound of x



================================================
FILE: readme_images/file_name_description
================================================
file name explanation

p: padded image
c: cropped image
lb: left bottom
lt: left top
rb: right bottom
rt: right top



================================================
FILE: src/accuracy.py
================================================
#from post_processing import *
import numpy as np
from PIL import Image
import glob as gl
import numpy as np
from PIL import Image
import torch


def accuracy_check(mask, prediction):
    ims = [mask, prediction]
    np_ims = []
    for item in ims:
        if 'str' in str(type(item)):
            item = np.array(Image.open(item))
        elif 'PIL' in str(type(item)):
            item = np.array(item)
        elif 'torch' in str(type(item)):
            item = item.numpy()
        np_ims.append(item)

    compare = np.equal(np_ims[0], np_ims[1])
    accuracy = np.sum(compare)

    return accuracy/len(np_ims[0].flatten())


def accuracy_check_for_batch(masks, predictions, batch_size):
    total_acc = 0
    for index in range(batch_size):
        total_acc += accuracy_check(masks[index], predictions[index])
    return total_acc/batch_size


"""
def accuracy_compare(prediction_folder, true_mask_folder):
    ''' Output average accuracy of all prediction results and their corresponding true masks.
    Args
        prediction_folder : folder of the prediction results
        true_mask_folder : folder of the corresponding true masks
    Returns
        a tuple of (original_accuracy, posprocess_accuracy)
    '''

    # Bring in the images
    all_prediction = gl.glob(prediction_folder)
    all_mask = gl.glob(true_mask_folder)

    # Initiation
    num_files = len(all_prediction)
    count = 0
    postprocess_acc = 0
    original_acc = 0

    while count != num_files:

        # Prepare the arrays to be further processed.
        prediction_processed = postprocess(all_prediction[count])
        prediction_image = Image.open(all_prediction[count])
        mask = Image.open(all_mask[count])

        # converting the PIL variables into numpy array
        prediction_np = np.asarray(prediction_image)
        mask_np = np.asarray(mask)

        # Calculate the accuracy of original and postprocessed image
        postprocess_acc += accuracy_check(mask_np, prediction_processed)
        original_acc += accuracy_check(mask_np, prediction_np)
        # check individual accuracy
        print(str(count) + 'th post acc:', accuracy_check(mask_np, prediction_processed))
        print(str(count) + 'th original acc:', accuracy_check(mask_np, prediction_np))

        # Move onto the next prediction/mask image
        count += 1

    # Average of all the accuracies
    postprocess_acc = postprocess_acc / num_files
    original_acc = original_acc / num_files

    return (original_acc, postprocess_acc)
"""

# Experimenting
if __name__ == '__main__':
    '''
    predictions = 'result/*.png'
    masks = '../data/val/masks/*.png'

    result = accuracy_compare(predictions, masks)
    print('Original Result :', result[0])
    print('Postprocess result :', result[1])
    '''


================================================
FILE: src/advanced_model.py
================================================
# full assembly of the sub-parts to form the complete net
import torch
import torch.nn as nn
from torch.autograd import Variable
import numpy as np
from PIL import Image
from torch.nn.functional import sigmoid


class Double_conv(nn.Module):

    '''(conv => ReLU) * 2 => MaxPool2d'''

    def __init__(self, in_ch, out_ch):
        """
        Args:
            in_ch(int) : input channel
            out_ch(int) : output channel
        """
        super(Double_conv, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(in_ch, out_ch, 3, padding=0, stride=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_ch, out_ch, 3, padding=0, stride=1),
            nn.ReLU(inplace=True)
        )

    def forward(self, x):
        x = self.conv(x)
        return x


class Conv_down(nn.Module):

    '''(conv => ReLU) * 2 => MaxPool2d'''

    def __init__(self, in_ch, out_ch):
        """
        Args:
            in_ch(int) : input channel
            out_ch(int) : output channel
        """
        super(Conv_down, self).__init__()
        self.conv = Double_conv(in_ch, out_ch)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)

    def forward(self, x):
        x = self.conv(x)
        pool_x = self.pool(x)
        return pool_x, x


class Conv_up(nn.Module):

    '''(conv => ReLU) * 2 => MaxPool2d'''

    def __init__(self, in_ch, out_ch):
        """
        Args:
            in_ch(int) : input channel
            out_ch(int) : output channel
        """
        super(Conv_up, self).__init__()
        self.up = nn.ConvTranspose2d(in_ch, out_ch, kernel_size=2, stride=2)
        self.conv = Double_conv(in_ch, out_ch)

    def forward(self, x1, x2):
        x1 = self.up(x1)
        x1_dim = x1.size()[2]
        x2 = extract_img(x1_dim, x2)
        x1 = torch.cat((x1, x2), dim=1)
        x1 = self.conv(x1)
        return x1


def extract_img(size, in_tensor):
    """
    Args:
        size(int) : size of cut
        in_tensor(tensor) : tensor to be cut
    """
    dim1, dim2 = in_tensor.size()[2:]
    in_tensor = in_tensor[:, :, int((dim1-size)/2):int((dim1+size)/2),
                          int((dim2-size)/2):int((dim2+size)/2)]
    return in_tensor


class CleanU_Net(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(CleanU_Net, self).__init__()
        self.Conv_down1 = Conv_down(in_channels, 64)
        self.Conv_down2 = Conv_down(64, 128)
        self.Conv_down3 = Conv_down(128, 256)
        self.Conv_down4 = Conv_down(256, 512)
        self.Conv_down5 = Conv_down(512, 1024)
        self.Conv_up1 = Conv_up(1024, 512)
        self.Conv_up2 = Conv_up(512, 256)
        self.Conv_up3 = Conv_up(256, 128)
        self.Conv_up4 = Conv_up(128, 64)
        self.Conv_out = nn.Conv2d(64, out_channels, 1, padding=0, stride=1)
        #self.Conv_final = nn.Conv2d(out_channels, out_channels, 1, padding=0, stride=1)

    def forward(self, x):

        x, conv1 = self.Conv_down1(x)
        #print("dConv1 => down1|", x.shape)
        x, conv2 = self.Conv_down2(x)
        #print("dConv2 => down2|", x.shape)
        x, conv3 = self.Conv_down3(x)
        #print("dConv3 => down3|", x.shape)
        x, conv4 = self.Conv_down4(x)
        #print("dConv4 => down4|", x.shape)
        _, x = self.Conv_down5(x)
        #print("dConv5|", x.shape)
        x = self.Conv_up1(x, conv4)
        #print("up1 => uConv1|", x.shape)
        x = self.Conv_up2(x, conv3)
        #print("up2 => uConv2|", x.shape)
        x = self.Conv_up3(x, conv2)
        #print("up3 => uConv3|", x.shape)
        x = self.Conv_up4(x, conv1)
        x = self.Conv_out(x)
        #x = self.Conv_final(x)

        return x


if __name__ == "__main__":
    # A full forward pass
    im = torch.randn(1, 1, 572, 572)
    model = CleanU_Net(1, 2)
    x = model(im)
    print(x.shape)
    del model
    del x
    # print(x.shape)


================================================
FILE: src/dataset.py
================================================
import numpy as np
from PIL import Image
import glob
import torch
import torch.nn as nn
from torch.autograd import Variable
from random import randint
from torch.utils.data.dataset import Dataset
from pre_processing import *
from mean_std import *

Training_MEAN = 0.4911
Training_STDEV = 0.1658


class SEMDataTrain(Dataset):

    def __init__(self, image_path, mask_path, in_size=572, out_size=388):
        """
        Args:
            image_path (str): the path where the image is located
            mask_path (str): the path where the mask is located
            option (str): decide which dataset to import
        """
        # all file names
        self.mask_arr = glob.glob(str(mask_path) + "/*")
        self.image_arr = glob.glob(str(image_path) + str("/*"))
        self.in_size, self.out_size = in_size, out_size
        # Calculate len
        self.data_len = len(self.mask_arr)
        # calculate mean and stdev

    def __getitem__(self, index):
        """Get specific data corresponding to the index
        Args:
            index (int): index of the data
        Returns:
            Tensor: specific data on index which is converted to Tensor
        """
        """
        # GET IMAGE
        """
        single_image_name = self.image_arr[index]
        img_as_img = Image.open(single_image_name)
        # img_as_img.show()
        img_as_np = np.asarray(img_as_img)

        # Augmentation
        # flip {0: vertical, 1: horizontal, 2: both, 3: none}
        flip_num = randint(0, 3)
        img_as_np = flip(img_as_np, flip_num)

        # Noise Determine {0: Gaussian_noise, 1: uniform_noise
        if randint(0, 1):
            # Gaussian_noise
            gaus_sd, gaus_mean = randint(0, 20), 0
            img_as_np = add_gaussian_noise(img_as_np, gaus_mean, gaus_sd)
        else:
            # uniform_noise
            l_bound, u_bound = randint(-20, 0), randint(0, 20)
            img_as_np = add_uniform_noise(img_as_np, l_bound, u_bound)

        # Brightness
        pix_add = randint(-20, 20)
        img_as_np = change_brightness(img_as_np, pix_add)

        # Elastic distort {0: distort, 1:no distort}
        sigma = randint(6, 12)
        # sigma = 4, alpha = 34
        img_as_np, seed = add_elastic_transform(img_as_np, alpha=34, sigma=sigma, pad_size=20)

        # Crop the image
        img_height, img_width = img_as_np.shape[0], img_as_np.shape[1]
        pad_size = int((self.in_size - self.out_size)/2)
        img_as_np = np.pad(img_as_np, pad_size, mode="symmetric")
        y_loc, x_loc = randint(0, img_height-self.out_size), randint(0, img_width-self.out_size)
        img_as_np = cropping(img_as_np, crop_size=self.in_size, dim1=y_loc, dim2=x_loc)
        '''
        # Sanity Check for image
        img1 = Image.fromarray(img_as_np)
        img1.show()
        '''
        # Normalize the image
        img_as_np = normalization2(img_as_np, max=1, min=0)
        img_as_np = np.expand_dims(img_as_np, axis=0)  # add additional dimension
        img_as_tensor = torch.from_numpy(img_as_np).float()  # Convert numpy array to tensor

        """
        # GET MASK
        """
        single_mask_name = self.mask_arr[index]
        msk_as_img = Image.open(single_mask_name)
        # msk_as_img.show()
        msk_as_np = np.asarray(msk_as_img)

        # flip the mask with respect to image
        msk_as_np = flip(msk_as_np, flip_num)

        # elastic_transform of mask with respect to image

        # sigma = 4, alpha = 34, seed = from image transformation
        msk_as_np, _ = add_elastic_transform(
            msk_as_np, alpha=34, sigma=sigma, seed=seed, pad_size=20)
        msk_as_np = approximate_image(msk_as_np)  # images only with 0 and 255

        # Crop the mask
        msk_as_np = cropping(msk_as_np, crop_size=self.out_size, dim1=y_loc, dim2=x_loc)
        '''
        # Sanity Check for mask
        img2 = Image.fromarray(msk_as_np)
        img2.show()
        '''

        # Normalize mask to only 0 and 1
        msk_as_np = msk_as_np/255
        # msk_as_np = np.expand_dims(msk_as_np, axis=0)  # add additional dimension
        msk_as_tensor = torch.from_numpy(msk_as_np).long()  # Convert numpy array to tensor

        return (img_as_tensor, msk_as_tensor)

    def __len__(self):
        """
        Returns:
            length (int): length of the data
        """
        return self.data_len


class SEMDataVal(Dataset):
    def __init__(self, image_path, mask_path, in_size=572, out_size=388):
        '''
        Args:
            image_path = path where test images are located
            mask_path = path where test masks are located
        '''
        # paths to all images and masks
        self.mask_arr = glob.glob(str(mask_path) + str("/*"))
        self.image_arr = glob.glob(str(image_path) + str("/*"))
        self.in_size = in_size
        self.out_size = out_size
        self.data_len = len(self.mask_arr)

    def __getitem__(self, index):
        """Get specific data corresponding to the index
        Args:
            index : an integer variable that calls (indext)th image in the
                    path
        Returns:
            Tensor: 4 cropped data on index which is converted to Tensor
        """
        single_image = self.image_arr[index]
        img_as_img = Image.open(single_image)
        # img_as_img.show()
        # Convert the image into numpy array
        img_as_np = np.asarray(img_as_img)

        # Make 4 cropped image (in numpy array form) using values calculated above
        # Cropped images will also have paddings to fit the model.
        pad_size = int((self.in_size - self.out_size)/2)
        img_as_np = np.pad(img_as_np, pad_size, mode="symmetric")
        img_as_np = multi_cropping(img_as_np,
                                   crop_size=self.in_size,
                                   crop_num1=2, crop_num2=2)

        # Empty list that will be filled in with arrays converted to tensor
        processed_list = []

        for array in img_as_np:

            # SANITY CHECK: SEE THE CROPPED & PADDED IMAGES
            #array_image = Image.fromarray(array)

            # Normalize the cropped arrays
            img_to_add = normalization2(array, max=1, min=0)
            # Convert normalized array into tensor
            processed_list.append(img_to_add)

        img_as_tensor = torch.Tensor(processed_list)
        #  return tensor of 4 cropped images
        #  top left, top right, bottom left, bottom right respectively.

        """
        # GET MASK
        """
        single_mask_name = self.mask_arr[index]
        msk_as_img = Image.open(single_mask_name)
        # msk_as_img.show()
        msk_as_np = np.asarray(msk_as_img)
        # Normalize mask to only 0 and 1
        msk_as_np = multi_cropping(msk_as_np,
                                   crop_size=self.out_size,
                                   crop_num1=2, crop_num2=2)

        msk_as_np = msk_as_np/255

        # msk_as_np = np.expand_dims(msk_as_np, axis=0)  # add additional dimension
        msk_as_tensor = torch.from_numpy(msk_as_np).long()  # Convert numpy array to tensor
        original_msk = torch.from_numpy(np.asarray(msk_as_img))
        return (img_as_tensor, msk_as_tensor, original_msk)

    def __len__(self):

        return self.data_len


class SEMDataTest(Dataset):

    def __init__(self, image_path, in_size=572, out_size=388):
        '''
        Args:
            image_path = path where test images are located
            mask_path = path where test masks are located
        '''
        # paths to all images and masks

        self.image_arr = glob.glob(str(image_path) + str("/*"))
        self.in_size = in_size
        self.out_size = out_size
        self.data_len = len(self.image_arr)

    def __getitem__(self, index):
        '''Get specific data corresponding to the index
        Args:
            index: an integer variable that calls(indext)th image in the
                path
        Returns:
            Tensor: 4 cropped data on index which is converted to Tensor
        '''

        single_image = self.image_arr[index]
        img_as_img = Image.open(single_image)
        # img_as_img.show()
        # Convert the image into numpy array
        img_as_np = np.asarray(img_as_img)

        pad_size = int((self.in_size - self.out_size)/2)
        img_as_np = np.pad(img_as_np, pad_size, mode="symmetric")
        img_as_np = multi_cropping(img_as_np,
                                   crop_size=self.in_size,
                                   crop_num1=2, crop_num2=2)

        # Empty list that will be filled in with arrays converted to tensor
        processed_list = []

        for array in img_as_np:

            # SANITY CHECK: SEE THE PADDED AND CROPPED IMAGES
            # array_image = Image.fromarray(array)

            # Normalize the cropped arrays
            img_to_add = normalization2(array, max=1, min=0)
            # Convert normalized array into tensor
            processed_list.append(img_to_add)

        img_as_tensor = torch.Tensor(processed_list)
        #  return tensor of 4 cropped images
        #  top left, top right, bottom left, bottom right respectively.
        return img_as_tensor

    def __len__(self):

        return self.data_len


if __name__ == "__main__":

    SEM_train = SEMDataTrain(
        '../data/train/images', '../data/train/masks')
    SEM_test = SEMDataTest(
        '../data/test/images/', '../data/test/masks')
    SEM_val = SEMDataVal('../data/val/images', '../data/val/masks')

    imag_1, msk = SEM_train.__getitem__(0)


================================================
FILE: src/main.py
================================================
from advanced_model import CleanU_Net
from dataset import *
import torch
import torch.nn as nn
from torch.autograd import Variable
import numpy as np
from PIL import Image
from modules import *
from save_history import *


if __name__ == "__main__":
    # Dataset begin
    SEM_train = SEMDataTrain(
        '../data/train/images', '../data/train/masks')

    # TO DO: finish test data loading
    SEM_test = SEMDataTest(
        '../data/test/images/')
    SEM_val = SEMDataVal(
        '../data/val/images', '../data/val/masks')
    # Dataset end

    # Dataloader begins
    SEM_train_load = \
        torch.utils.data.DataLoader(dataset=SEM_train,
                                    num_workers=16, batch_size=2, shuffle=True)
    SEM_val_load = \
        torch.utils.data.DataLoader(dataset=SEM_val,
                                    num_workers=3, batch_size=1, shuffle=True)

    SEM_test_load = \
        torch.utils.data.DataLoader(dataset=SEM_test,
                                    num_workers=3, batch_size=1, shuffle=False)

    # Dataloader end

    # Model
    model = CleanU_Net(in_channels=1, out_channels=2)
    #model = CleanU_Net()
    model = torch.nn.DataParallel(model, device_ids=list(
        range(torch.cuda.device_count()))).cuda()

    # Loss function
    criterion = nn.CrossEntropyLoss()

    # Optimizerd
    optimizer = torch.optim.RMSprop(model.module.parameters(), lr=0.001)

    # Parameters
    epoch_start = 0
    epoch_end = 2000

    # Saving History to csv
    header = ['epoch', 'train loss', 'train acc', 'val loss', 'val acc']
    save_file_name = "../history/RMS/history_RMS3.csv"
    save_dir = "../history/RMS"

    # Saving images and models directories
    model_save_dir = "../history/RMS/saved_models3"
    image_save_path = "../history/RMS/result_images3"

    # Train
    print("Initializing Training!")
    for i in range(epoch_start, epoch_end):
        # train the model
        train_model(model, SEM_train_load, criterion, optimizer)
        train_acc, train_loss = get_loss_train(model, SEM_train_load, criterion)

        #train_loss = train_loss / len(SEM_train)
        print('Epoch', str(i+1), 'Train loss:', train_loss, "Train acc", train_acc)

        # Validation every 5 epoch
        if (i+1) % 5 == 0:
            val_acc, val_loss = validate_model(
                model, SEM_val_load, criterion, i+1, True, image_save_path)
            print('Val loss:', val_loss, "val acc:", val_acc)
            values = [i+1, train_loss, train_acc, val_loss, val_acc]
            export_history(header, values, save_dir, save_file_name)

            if (i+1) % 100 == 0:  # save model every 10 epoch
                save_models(model, model_save_dir, i+1)

"""
# Test
print("generate test prediction")
test_model("../history/RMS/saved_models/model_epoch_440.pwf",
           SEM_test_load, 440, "../history/RMS/result_images_test")
"""


================================================
FILE: src/mean_std.py
================================================
import numpy as np
from PIL import Image
import glob


def normalize_image(image):
    """
    Args:
        image : a string of name of image file
    Return:
        image_asarray : numpy array of the image
                        that is normalized by being divided by 255
    """

    img_opened = Image.open(image)
    img_asarray = np.asarray(img_opened)
    img_asarray = img_asarray / 255

    return img_asarray


def find_mean(image_path):
    """
    Args:
        image_path : pathway of all images
    Return :
        mean : mean value of all the images
    """
    all_images = glob.glob(str(image_path) + str("/*"))
    num_images = len(all_images)
    mean_sum = 0

    for image in all_images:
        img_asarray = normalize_image(image)
        individual_mean = np.mean(img_asarray)
        mean_sum += individual_mean

    # Divide the sum of all values by the number of images present
    mean = mean_sum / num_images

    return mean


def find_stdev(image_path):
    """
    Args:
        image_path : pathway of all images
    Return :
        stdev : standard deviation of all pixels
    """
    # Initiation
    all_images = glob.glob(str(image_path) + str("/*"))
    num_images = len(all_images)

    # Recall mean value from function above: def Mean(path)
    mean_value = find_mean(image_path)
    std_sum = 0

    for image in all_images:
        img_asarray = normalize_image(image)
        individual_stdev = np.std(img_asarray)
        std_sum += individual_stdev

    std = std_sum / num_images

    return std


# Experimenting
if __name__ == '__main__':
    image_path = '../data/train/images'

    print('for training images,')
    print('mean:', find_mean(image_path))
    print('stdev:', find_stdev(image_path))


================================================
FILE: src/modules.py
================================================
import numpy as np
from PIL import Image
import torch
import torch.nn as nn
from torch.autograd import Variable
from dataset import *
import torch.nn as nn
from accuracy import accuracy_check, accuracy_check_for_batch
import csv
import os


def train_model(model, data_train, criterion, optimizer):
    """Train the model and report validation error with training error
    Args:
        model: the model to be trained
        criterion: loss function
        data_train (DataLoader): training dataset
    """
    model.train()
    for batch, (images, masks) in enumerate(data_train):
        images = Variable(images.cuda())
        masks = Variable(masks.cuda())
        outputs = model(images)
        # print(masks.shape, outputs.shape)
        loss = criterion(outputs, masks)
        optimizer.zero_grad()
        loss.backward()
        # Update weights
        optimizer.step()
    # total_loss = get_loss_train(model, data_train, criterion)


def get_loss_train(model, data_train, criterion):
    """
        Calculate loss over train set
    """
    model.eval()
    total_acc = 0
    total_loss = 0
    for batch, (images, masks) in enumerate(data_train):
        with torch.no_grad():
            images = Variable(images.cuda())
            masks = Variable(masks.cuda())
            outputs = model(images)
            loss = criterion(outputs, masks)
            preds = torch.argmax(outputs, dim=1).float()
            acc = accuracy_check_for_batch(masks.cpu(), preds.cpu(), images.size()[0])
            total_acc = total_acc + acc
            total_loss = total_loss + loss.cpu().item()
    return total_acc/(batch+1), total_loss/(batch + 1)


def validate_model(model, data_val, criterion, epoch, make_prediction=True, save_folder_name='prediction'):
    """
        Validation run
    """
    # calculating validation loss
    total_val_loss = 0
    total_val_acc = 0
    for batch, (images_v, masks_v, original_msk) in enumerate(data_val):
        stacked_img = torch.Tensor([]).cuda()
        for index in range(images_v.size()[1]):
            with torch.no_grad():
                image_v = Variable(images_v[:, index, :, :].unsqueeze(0).cuda())
                mask_v = Variable(masks_v[:, index, :, :].squeeze(1).cuda())
                # print(image_v.shape, mask_v.shape)
                output_v = model(image_v)
                total_val_loss = total_val_loss + criterion(output_v, mask_v).cpu().item()
                # print('out', output_v.shape)
                output_v = torch.argmax(output_v, dim=1).float()
                stacked_img = torch.cat((stacked_img, output_v))
        if make_prediction:
            im_name = batch  # TODO: Change this to real image name so we know
            pred_msk = save_prediction_image(stacked_img, im_name, epoch, save_folder_name)
            acc_val = accuracy_check(original_msk, pred_msk)
            total_val_acc = total_val_acc + acc_val

    return total_val_acc/(batch + 1), total_val_loss/((batch + 1)*4)


def test_model(model_path, data_test, epoch, save_folder_name='prediction'):
    """
        Test run
    """
    model = torch.load(model_path)
    model = torch.nn.DataParallel(model, device_ids=list(
        range(torch.cuda.device_count()))).cuda()
    model.eval()
    for batch, (images_t) in enumerate(data_test):
        stacked_img = torch.Tensor([]).cuda()
        for index in range(images_t.size()[1]):
            with torch.no_grad():
                image_t = Variable(images_t[:, index, :, :].unsqueeze(0).cuda())
                # print(image_v.shape, mask_v.shape)
                output_t = model(image_t)
                output_t = torch.argmax(output_t, dim=1).float()
                stacked_img = torch.cat((stacked_img, output_t))
        im_name = batch  # TODO: Change this to real image name so we know
        _ = save_prediction_image(stacked_img, im_name, epoch, save_folder_name)
    print("Finish Prediction!")


def save_prediction_image(stacked_img, im_name, epoch, save_folder_name="result_images", save_im=True):
    """save images to save_path
    Args:
        stacked_img (numpy): stacked cropped images
        save_folder_name (str): saving folder name
    """
    div_arr = division_array(388, 2, 2, 512, 512)
    img_cont = image_concatenate(stacked_img.cpu().data.numpy(), 2, 2, 512, 512)
    img_cont = polarize((img_cont)/div_arr)*255
    img_cont_np = img_cont.astype('uint8')
    img_cont = Image.fromarray(img_cont_np)
    # organize images in every epoch
    desired_path = save_folder_name + '/epoch_' + str(epoch) + '/'
    # Create the path if it does not exist
    if not os.path.exists(desired_path):
        os.makedirs(desired_path)
    # Save Image!
    export_name = str(im_name) + '.png'
    img_cont.save(desired_path + export_name)
    return img_cont_np


def polarize(img):
    ''' Polarize the value to zero and one
    Args:
        img (numpy): numpy array of image to be polarized
    return:
        img (numpy): numpy array only with zero and one
    '''
    img[img >= 0.5] = 1
    img[img < 0.5] = 0
    return img


"""
def test_SEM(model, data_test,  folder_to_save):
    '''Test the model with test dataset
    Args:
        model: model to be tested
        data_test (DataLoader): test dataset
        folder_to_save (str): path that the predictions would be saved
    '''
    for i, (images) in enumerate(data_test):

        print(images)
        stacked_img = torch.Tensor([])
        for j in range(images.size()[1]):
            image = Variable(images[:, j, :, :].unsqueeze(0).cuda())
            output = model(image.cuda())
            print(output)
            print("size", output.size())
            output = torch.argmax(output, dim=1).float()
            print("size", output.size())
            stacked_img = torch.cat((stacked_img, output))
        div_arr = division_array(388, 2, 2, 512, 512)
        print(stacked_img.size())
        img_cont = image_concatenate(stacked_img.data.numpy(), 2, 2, 512, 512)
        final_img = (img_cont*255/div_arr)
        print(final_img)
        final_img = final_img.astype("uint8")
        break
    return final_img
"""


if __name__ == '__main__':
    SEM_train = SEMDataTrain(
        '../data/train/images', '../data/train/masks')
    SEM_train_load = torch.utils.data.DataLoader(dataset=SEM_train,
                                                 num_workers=3, batch_size=10, shuffle=True)
    get_loss_train()


================================================
FILE: src/post_processing.py
================================================
import numpy as np
from matplotlib import pyplot as plt


def postprocess(image_path):
    ''' postprocessing of the prediction output
    Args
        image_path : path of the image
    Returns
        watershed_grayscale : numpy array of postprocessed image (in grayscale)
    '''

    # Bring in the image
    img_original = cv2.imread(image_path)
    img = cv2.imread(image_path)

    # In case the input image has 3 channels (RGB), convert to 1 channel (grayscale)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Use threshold => Image will have values either 0 or 255 (black or white)
    ret, bin_image = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

    # Remove Hole or noise through the use of opening, closing in Morphology module
    kernel = np.ones((1, 1), np.uint8)
    kernel1 = np.ones((3, 3), np.uint8)

    # remove noise in
    closing = cv2.morphologyEx(bin_image, cv2.MORPH_CLOSE, kernel, iterations=1)

    # make clear distinction of the background
    # Incerease/emphasize the white region.
    sure_bg = cv2.dilate(closing, kernel1, iterations=1)

    # calculate the distance to the closest zero pixel for each pixel of the source.
    # Adjust the threshold value with respect to the maximum distance. Lower threshold, more information.
    dist_transform = cv2.distanceTransform(closing, cv2.DIST_L2, 5)
    ret, sure_fg = cv2.threshold(dist_transform, 0.2*dist_transform.max(), 255, 0)
    sure_fg = np.uint8(sure_fg)

    # Unknown is the region of background with foreground excluded.
    unknown = cv2.subtract(sure_bg, sure_fg)

    # labelling on the foreground.
    ret, markers = cv2.connectedComponents(sure_fg)
    markers_plus1 = markers + 1
    markers_plus1[unknown == 255] = 0

    # Appy watershed and label the borders
    markers_watershed = cv2.watershed(img, markers_plus1)

    # See the watershed result in a clear white page.
    img_x, img_y = img_original.shape[0], img_original.shape[1]  # 512x512
    white, white_color = np.zeros((img_x, img_y, 3)), np.zeros((img_x, img_y, 3))
    white += 255
    white_color += 255
    # 1 in markers_watershed indicate the background value
    # label everything not indicated as background value
    white[markers_watershed != 1] = [0, 0, 0]  # grayscale version
    white_color[markers_watershed != 1] = [255, 0, 0]  # RGB version

    # Convert to numpy array for later processing
    white_np = np.asarray(white)  # 512x512x3
    watershed_grayscale = white_np.transpose(2, 0, 1)[0, :, :]  # convert to 1 channel (grayscale)
    img[markers_watershed != 1] = [255, 0, 0]

    return watershed_grayscale

    '''
    Visualizing all the intermediate processes

    images = [img_original, gray,bin_image, closing, sure_bg,  dist_transform, sure_fg, unknown, markers, markers_watershed, white_color, white, img]
    titles = ['Original', '1. Grayscale','2. Binary','3. Closing','Sure BG','Distance','Sure FG','Unknown','Markers', 'Markers_Watershed','Result', 'Result gray','Result Overlapped']
    CMAP = [None, 'gray', 'gray','gray','gray',None,'gray','gray',None, None, None, None,'gray']


    for i in range(len(images)):
        plt.subplot(4,4,i+1),plt.imshow(images[i], cmap=CMAP[i]),plt.title(titles[i]),plt.xticks([]),plt.yticks([])

    plt.show()
    '''


if __name__ == '__main__':
    from PIL import Image

    print(postprocess('../data/train/masks/25.png'))


================================================
FILE: src/pre_processing.py
================================================
import numpy as np
from scipy.ndimage.interpolation import map_coordinates
from scipy.ndimage.filters import gaussian_filter
from random import randint


def add_elastic_transform(image, alpha, sigma, pad_size=30, seed=None):
    """
    Args:
        image : numpy array of image
        alpha : α is a scaling factor
        sigma :  σ is an elasticity coefficient
        random_state = random integer
        Return :
        image : elastically transformed numpy array of image
    """
    image_size = int(image.shape[0])
    image = np.pad(image, pad_size, mode="symmetric")
    if seed is None:
        seed = randint(1, 100)
        random_state = np.random.RandomState(seed)
    else:
        random_state = np.random.RandomState(seed)
    shape = image.shape
    dx = gaussian_filter((random_state.rand(*shape) * 2 - 1),
                         sigma, mode="constant", cval=0) * alpha
    dy = gaussian_filter((random_state.rand(*shape) * 2 - 1),
                         sigma, mode="constant", cval=0) * alpha

    x, y = np.meshgrid(np.arange(shape[1]), np.arange(shape[0]))
    indices = np.reshape(y+dy, (-1, 1)), np.reshape(x+dx, (-1, 1))
    return cropping(map_coordinates(image, indices, order=1).reshape(shape), 512, pad_size, pad_size), seed


def flip(image, option_value):
    """
    Args:
        image : numpy array of image
        option_value = random integer between 0 to 3
    Return :
        image : numpy array of flipped image
    """
    if option_value == 0:
        # vertical
        image = np.flip(image, option_value)
    elif option_value == 1:
        # horizontal
        image = np.flip(image, option_value)
    elif option_value == 2:
        # horizontally and vertically flip
        image = np.flip(image, 0)
        image = np.flip(image, 1)
    else:
        image = image
        # no effect
    return image


def add_gaussian_noise(image, mean=0, std=1):
    """
    Args:
        image : numpy array of image
        mean : pixel mean of image
        standard deviation : pixel standard deviation of image
    Return :
        image : numpy array of image with gaussian noise added
    """
    gaus_noise = np.random.normal(mean, std, image.shape)
    image = image.astype("int16")
    noise_img = image + gaus_noise
    image = ceil_floor_image(image)
    return noise_img


def add_uniform_noise(image, low=-10, high=10):
    """
    Args:
        image : numpy array of image
        low : lower boundary of output interval
        high : upper boundary of output interval
    Return :
        image : numpy array of image with uniform noise added
    """
    uni_noise = np.random.uniform(low, high, image.shape)
    image = image.astype("int16")
    noise_img = image + uni_noise
    image = ceil_floor_image(image)
    return noise_img


def change_brightness(image, value):
    """
    Args:
        image : numpy array of image
        value : brightness
    Return :
        image : numpy array of image with brightness added
    """
    image = image.astype("int16")
    image = image + value
    image = ceil_floor_image(image)
    return image


def ceil_floor_image(image):
    """
    Args:
        image : numpy array of image in datatype int16
    Return :
        image : numpy array of image in datatype uint8 with ceilling(maximum 255) and flooring(minimum 0)
    """
    image[image > 255] = 255
    image[image < 0] = 0
    image = image.astype("uint8")
    return image


def approximate_image(image):
    """
    Args:
        image : numpy array of image in datatype int16
    Return :
        image : numpy array of image in datatype uint8 only with 255 and 0
    """
    image[image > 127.5] = 255
    image[image < 127.5] = 0
    image = image.astype("uint8")
    return image


def normalization1(image, mean, std):
    """ Normalization using mean and std
    Args :
        image : numpy array of image
        mean :
    Return :
        image : numpy array of image with values turned into standard scores
    """

    image = image / 255  # values will lie between 0 and 1.
    image = (image - mean) / std

    return image


def normalization2(image, max, min):
    """Normalization to range of [min, max]
    Args :
        image : numpy array of image
        mean :
    Return :
        image : numpy array of image with values turned into standard scores
    """
    image_new = (image - np.min(image))*(max - min)/(np.max(image)-np.min(image)) + min
    return image_new


def stride_size(image_len, crop_num, crop_size):
    """return stride size
    Args :
        image_len(int) : length of one size of image (width or height)
        crop_num(int) : number of crop in certain direction
        crop_size(int) : size of crop
    Return :
        stride_size(int) : stride size
    """
    return int((image_len - crop_size)/(crop_num - 1))


def multi_cropping(image, crop_size, crop_num1, crop_num2):
    """crop the image and pad it to in_size
    Args :
        images : numpy arrays of images
        crop_size(int) : size of cropped image
        crop_num2 (int) : number of crop in horizontal way
        crop_num1 (int) : number of crop in vertical way
    Return :
        cropped_imgs : numpy arrays of stacked images
    """

    img_height, img_width = image.shape[0], image.shape[1]
    assert crop_size*crop_num1 >= img_width and crop_size * \
        crop_num2 >= img_height, "Whole image cannot be sufficiently expressed"
    assert crop_num1 <= img_width - crop_size + 1 and crop_num2 <= img_height - \
        crop_size + 1, "Too many number of crops"

    cropped_imgs = []
    # int((img_height - crop_size)/(crop_num1 - 1))
    dim1_stride = stride_size(img_height, crop_num1, crop_size)
    # int((img_width - crop_size)/(crop_num2 - 1))
    dim2_stride = stride_size(img_width, crop_num2, crop_size)
    for i in range(crop_num1):
        for j in range(crop_num2):
            cropped_imgs.append(cropping(image, crop_size,
                                         dim1_stride*i, dim2_stride*j))
    return np.asarray(cropped_imgs)


# IT IS NOT USED FOR PAD AND CROP DATA OPERATION
# IF YOU WANT TO USE CROP AND PAD USE THIS FUNCTION
"""
def multi_padding(images, in_size, out_size, mode):
    '''Pad the images to in_size
    Args :
        images : numpy array of images (CxHxW)
        in_size(int) : the input_size of model (512)
        out_size(int) : the output_size of model (388)
        mode(str) : mode of padding
    Return :
        padded_imgs: numpy arrays of padded images
    '''
    pad_size = int((in_size - out_size)/2)
    padded_imgs = []
    for num in range(images.shape[0]):
        padded_imgs.append(add_padding(images[num], in_size, out_size, mode=mode))
    return np.asarray(padded_imgs)

"""


def cropping(image, crop_size, dim1, dim2):
    """crop the image and pad it to in_size
    Args :
        images : numpy array of images
        crop_size(int) : size of cropped image
        dim1(int) : vertical location of crop
        dim2(int) : horizontal location of crop
    Return :
        cropped_img: numpy array of cropped image
    """
    cropped_img = image[dim1:dim1+crop_size, dim2:dim2+crop_size]
    return cropped_img


def add_padding(image, in_size, out_size, mode):
    """Pad the image to in_size
    Args :
        images : numpy array of images
        in_size(int) : the input_size of model
        out_size(int) : the output_size of model
        mode(str) : mode of padding
    Return :
        padded_img: numpy array of padded image
    """
    pad_size = int((in_size - out_size)/2)
    padded_img = np.pad(image, pad_size, mode=mode)
    return padded_img


def division_array(crop_size, crop_num1, crop_num2, dim1, dim2):
    """Make division array
    Args :
        crop_size(int) : size of cropped image
        crop_num2 (int) : number of crop in horizontal way
        crop_num1 (int) : number of crop in vertical way
        dim1(int) : vertical size of output
        dim2(int) : horizontal size_of_output
    Return :
        div_array : numpy array of numbers of 1,2,4
    """
    div_array = np.zeros([dim1, dim2])  # make division array
    one_array = np.ones([crop_size, crop_size])  # one array to be added to div_array
    dim1_stride = stride_size(dim1, crop_num1, crop_size)  # vertical stride
    dim2_stride = stride_size(dim2, crop_num2, crop_size)  # horizontal stride
    for i in range(crop_num1):
        for j in range(crop_num2):
            # add ones to div_array at specific position
            div_array[dim1_stride*i:dim1_stride*i + crop_size,
                      dim2_stride*j:dim2_stride*j + crop_size] += one_array
    return div_array


def image_concatenate(image, crop_num1, crop_num2, dim1, dim2):
    """concatenate images
    Args :
        image : output images (should be square)
        crop_num2 (int) : number of crop in horizontal way (2)
        crop_num1 (int) : number of crop in vertical way (2)
        dim1(int) : vertical size of output (512)
        dim2(int) : horizontal size_of_output (512)
    Return :
        div_array : numpy arrays of numbers of 1,2,4
    """
    crop_size = image.shape[1]  # size of crop
    empty_array = np.zeros([dim1, dim2]).astype("float64")  # to make sure no overflow
    dim1_stride = stride_size(dim1, crop_num1, crop_size)  # vertical stride
    dim2_stride = stride_size(dim2, crop_num2, crop_size)  # horizontal stride
    index = 0
    for i in range(crop_num1):
        for j in range(crop_num2):
            # add image to empty_array at specific position
            empty_array[dim1_stride*i:dim1_stride*i + crop_size,
                        dim2_stride*j:dim2_stride*j + crop_size] += image[index]
            index += 1
    return empty_array


if __name__ == "__main__":
    from PIL import Image

    b = Image.open("../data/train/images/14.png")
    c = Image.open("../data/train/masks/14.png")

    original = np.array(b)
    originall = np.array(c)
    original_norm = normalization(original, max=1, min=0)
    print(original_norm)

    b = Image.open("../readme_images/original.png")
    original = np.array(b)
    """
    original1 = add_gaussian_noise(original, 0, 100)
    original1 = Image.fromarray(original1)
    original1.show()
    """
    original1 = add_uniform_noise(original, -100, 100)
    original1 = Image.fromarray(original1)
    original1.show()
    """
    original1 = change_brightness(original, 50)
    original1 = Image.fromarray(original1)
    original1.show()
    original1 = add_elastic_transform(original, 10, 4, 1)[0]
    original1 = Image.fromarray(original1)
    original1.show()
    """


================================================
FILE: src/result_visualization.py
================================================

import matplotlib.pyplot as plt
import matplotlib as mpl
import pandas as pd
import numpy as np

'''
For members who did not yet install the module "matplotlib",
    python3 -mpip install -U matplotlib
installation of tkinter is a prerequisite. If you do not have it,
    sudo apt install python3.6-tk
Now you won't have problems running this python file.
'''


def plotloss(csvfile):
    '''
    Args
        csvfile: name of the csv file
    Returns
        graph_loss: trend of loss values over epoch
    '''

    # Bring in the csv file
    loss_values = pd.read_csv(csvfile)

    # Initiation
    epoch = loss_values.iloc[:, 0]
    tr_loss = loss_values.iloc[:, 1]
    tr_acc = loss_values.iloc[:, 2]
    val_loss = np.asarray(loss_values.iloc[:, 3])
    val_acc = np.asarray(loss_values.iloc[:, 4])

    # Reduce the volume of data
    epoch_skip = epoch[::5]
    tr_loss_skip = tr_loss[::5]
    tr_acc_skip = tr_acc[::5]
    val_loss_skip = val_loss[::5]
    val_acc_skip = val_acc[::5]

    fig, ax1 = plt.subplots(figsize=(8, 6))
    ax2 = ax1.twinx()

    # Label and color the axes
    ax1.set_xlabel('Epoch', fontsize=16)
    ax1.set_ylabel('Loss', fontsize=16, color='black')
    ax2.set_ylabel('Accuracy', fontsize=16, color='black')

    # Plot valid/train losses
    ax1.plot(epoch_skip, tr_loss_skip, linewidth=2,
             ls='--', color='#c92508', label='Train loss')
    ax1.plot(epoch_skip, val_loss_skip, linewidth=2,
             color='#c92508', label='Validation loss')
    ax1.spines['left'].set_color('#f23d1d')
    # Coloring the ticks
    for label in ax1.get_yticklabels():
        label.set_color('#c92508')
        label.set_size(12)

    # Plot valid/trian accuracy
    ax2.plot(epoch_skip, tr_acc_skip, linewidth=2, ls='--',
             color='#2348ff', label='Train Accuracy')
    ax2.plot(epoch_skip, val_acc_skip, linewidth=2,
             color='#2348ff', label='Validation Accuracy')
    ax2.spines['right'].set_color('#2348ff')
    # Coloring the ticks
    for label in ax2.get_yticklabels():
        label.set_color('#2348ff')
        label.set_size(12)

    # Manually setting the y-axis ticks
    yticks = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
    ax1.set_yticks(yticks)
    ax2.set_yticks(yticks)

    for label in ax1.get_xticklabels():
        label.set_size(12)

    # Modification of the overall graph
    fig.legend(ncol=4, loc=9, fontsize=12)
    plt.xlim(xmin=0)
    ax2.set_ylim(ymax=1, ymin=0)
    ax1.set_ylim(ymax=1, ymin=0)
    plt.xlabel('epochs')
    plt.title("Adam optimizer", weight="bold")
    plt.grid(True, axis='y')

    # return train_loss, valid_loss


if __name__ == '__main__':
    file = '../history/csv/Adam.csv'
    #file = '../history/SGD/history_SGD4.csv'
    plt.show(plotloss(file))


================================================
FILE: src/save_history.py
================================================
import os
import csv
import torch


def export_history(header, value, folder, file_name):
    """ export data to csv format
    Args:
        header (list): headers of the column
        value (list): values of correspoding column
        folder (list): folder path
        file_name: file name with path
    """
    # if folder does not exists make folder
    if not os.path.exists(folder):
        os.makedirs(folder)

    file_existence = os.path.isfile(file_name)

    # if there is no file make file
    if file_existence == False:
        file = open(file_name, 'w', newline='')
        writer = csv.writer(file)
        writer.writerow(header)
        writer.writerow(value)
    # if there is file overwrite
    else:
        file = open(file_name, 'a', newline='')
        writer = csv.writer(file)
        writer.writerow(value)
    # close file when it is done with writing
    file.close()


def save_models(model, path, epoch):
    """Save model to given path
    Args:
        model: model to be saved
        path: path that the model would be saved
        epoch: the epoch the model finished training
    """
    if not os.path.exists(path):
        os.makedirs(path)
    torch.save(model, path+"/model_epoch_{0}.pwf".format(epoch))


================================================
FILE: src/simple_model.py
================================================
import torch
import torch.nn as nn
from torch.autograd import Variable
import numpy as np
from PIL import Image
from torch.nn.functional import sigmoid


class CleanU_Net(nn.Module):

    def __init__(self):

        super(CleanU_Net, self).__init__()

        # Conv block 1 - Down 1
        self.conv1_block = nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=32,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=32, out_channels=32,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
        )
        self.max1 = nn.MaxPool2d(kernel_size=2, stride=2)

        # Conv block 2 - Down 2
        self.conv2_block = nn.Sequential(
            nn.Conv2d(in_channels=32, out_channels=64,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=64, out_channels=64,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
        )
        self.max2 = nn.MaxPool2d(kernel_size=2, stride=2)

        # Conv block 3 - Down 3
        self.conv3_block = nn.Sequential(
            nn.Conv2d(in_channels=64, out_channels=128,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=128, out_channels=128,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
        )
        self.max3 = nn.MaxPool2d(kernel_size=2, stride=2)

        # Conv block 4 - Down 4
        self.conv4_block = nn.Sequential(
            nn.Conv2d(in_channels=128, out_channels=256,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=256, out_channels=256,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
        )
        self.max4 = nn.MaxPool2d(kernel_size=2, stride=2)

        # Conv block 5 - Down 5
        self.conv5_block = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=512,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=512, out_channels=512,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
        )

        # Up 1
        self.up_1 = nn.ConvTranspose2d(in_channels=512, out_channels=256, kernel_size=2, stride=2)

        # Up Conv block 1
        self.conv_up_1 = nn.Sequential(
            nn.Conv2d(in_channels=512, out_channels=256,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=256, out_channels=256,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
        )

        # Up 2
        self.up_2 = nn.ConvTranspose2d(in_channels=256, out_channels=128, kernel_size=2, stride=2)

        # Up Conv block 2
        self.conv_up_2 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=128,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=128, out_channels=128,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
        )

        # Up 3
        self.up_3 = nn.ConvTranspose2d(in_channels=128, out_channels=64, kernel_size=2, stride=2)

        # Up Conv block 3
        self.conv_up_3 = nn.Sequential(
            nn.Conv2d(in_channels=128, out_channels=64,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=64, out_channels=64,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
        )

        # Up 4
        self.up_4 = nn.ConvTranspose2d(in_channels=64, out_channels=32, kernel_size=2, stride=2)

        # Up Conv block 4
        self.conv_up_4 = nn.Sequential(
            nn.Conv2d(in_channels=64, out_channels=32,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=32, out_channels=32,
                      kernel_size=3, padding=0, stride=1),
            nn.ReLU(inplace=True),
        )

        # Final output
        self.conv_final = nn.Conv2d(in_channels=32, out_channels=2,
                                    kernel_size=1, padding=0, stride=1)

    def forward(self, x):
        # print('input', x.shape)

        # Down 1
        x = self.conv1_block(x)
        # print('after conv1', x.shape)
        conv1_out = x  # Save out1
        conv1_dim = x.shape[2]
        x = self.max1(x)
        # print('before conv2', x.shape)

        # Down 2
        x = self.conv2_block(x)
        # print('after conv2', x.shape)
        conv2_out = x
        conv2_dim = x.shape[2]
        x = self.max2(x)
        # print('before conv3', x.shape)

        # Down 3
        x = self.conv3_block(x)
        # print('after conv3', x.shape)
        conv3_out = x
        conv3_dim = x.shape[2]
        x = self.max3(x)
        # print('before conv4', x.shape)

        # Down 4
        x = self.conv4_block(x)
        # print('after conv5', x.shape)
        conv4_out = x
        conv4_dim = x.shape[2]
        x = self.max4(x)

        # Midpoint
        x = self.conv5_block(x)

        # Up 1
        x = self.up_1(x)
        # print('up_1', x.shape)
        lower = int((conv4_dim - x.shape[2]) / 2)
        upper = int(conv4_dim - lower)
        conv4_out_modified = conv4_out[:, :, lower:upper, lower:upper]
        x = torch.cat([x, conv4_out_modified], dim=1)
        # print('after cat_1', x.shape)
        x = self.conv_up_1(x)
        # print('after conv_1', x.shape)

        # Up 2
        x = self.up_2(x)
        # print('up_2', x.shape)
        lower = int((conv3_dim - x.shape[2]) / 2)
        upper = int(conv3_dim - lower)
        conv3_out_modified = conv3_out[:, :, lower:upper, lower:upper]
        x = torch.cat([x, conv3_out_modified], dim=1)
        # print('after cat_2', x.shape)
        x = self.conv_up_2(x)
        # print('after conv_2', x.shape)

        # Up 3
        x = self.up_3(x)
        # print('up_3', x.shape)
        lower = int((conv2_dim - x.shape[2]) / 2)
        upper = int(conv2_dim - lower)
        conv2_out_modified = conv2_out[:, :, lower:upper, lower:upper]
        x = torch.cat([x, conv2_out_modified], dim=1)
        # print('after cat_3', x.shape)
        x = self.conv_up_3(x)
        # print('after conv_3', x.shape)

        # Up 4
        x = self.up_4(x)
        # print('up_4', x.shape)
        lower = int((conv1_dim - x.shape[2]) / 2)
        upper = int(conv1_dim - lower)
        conv1_out_modified = conv1_out[:, :, lower:upper, lower:upper]
        x = torch.cat([x, conv1_out_modified], dim=1)
        # print('after cat_4', x.shape)
        x = self.conv_up_4(x)
        # print('after conv_4', x.shape)

        # Final output
        x = self.conv_final(x)

        return x


if __name__ == "__main__":
    # A full forward pass
    im = torch.randn(1, 1, 572, 572)
    model = CleanU_Net()
    x = model(im)
    # print(x.shape)
    del model
    del x
    # print(x.shape)
Download .txt
gitextract_h5owzdln/

├── .gitignore
├── LICENSE
├── README.md
├── readme_images/
│   ├── bright_10
│   ├── c_lb
│   ├── c_lt
│   ├── c_rb
│   ├── c_rt
│   ├── description
│   ├── division_matrix
│   ├── elastic_1
│   ├── file_name_description
│   ├── final_concate
│   ├── flip_both
│   ├── flip_hori
│   ├── flip_vert
│   ├── gn_10
│   ├── gn_100
│   ├── gn_50
│   ├── original_image
│   ├── un_100
│   ├── un_50
│   └── uniform_10
└── src/
    ├── accuracy.py
    ├── advanced_model.py
    ├── dataset.py
    ├── main.py
    ├── mean_std.py
    ├── modules.py
    ├── post_processing.py
    ├── pre_processing.py
    ├── result_visualization.py
    ├── save_history.py
    └── simple_model.py
Download .txt
SYMBOL INDEX (58 symbols across 10 files)

FILE: src/accuracy.py
  function accuracy_check (line 10) | def accuracy_check(mask, prediction):
  function accuracy_check_for_batch (line 28) | def accuracy_check_for_batch(masks, predictions, batch_size):

FILE: src/advanced_model.py
  class Double_conv (line 10) | class Double_conv(nn.Module):
    method __init__ (line 14) | def __init__(self, in_ch, out_ch):
    method forward (line 28) | def forward(self, x):
  class Conv_down (line 33) | class Conv_down(nn.Module):
    method __init__ (line 37) | def __init__(self, in_ch, out_ch):
    method forward (line 47) | def forward(self, x):
  class Conv_up (line 53) | class Conv_up(nn.Module):
    method __init__ (line 57) | def __init__(self, in_ch, out_ch):
    method forward (line 67) | def forward(self, x1, x2):
  function extract_img (line 76) | def extract_img(size, in_tensor):
  class CleanU_Net (line 88) | class CleanU_Net(nn.Module):
    method __init__ (line 89) | def __init__(self, in_channels, out_channels):
    method forward (line 103) | def forward(self, x):

FILE: src/dataset.py
  class SEMDataTrain (line 16) | class SEMDataTrain(Dataset):
    method __init__ (line 18) | def __init__(self, image_path, mask_path, in_size=572, out_size=388):
    method __getitem__ (line 33) | def __getitem__(self, index):
    method __len__ (line 121) | def __len__(self):
  class SEMDataVal (line 129) | class SEMDataVal(Dataset):
    method __init__ (line 130) | def __init__(self, image_path, mask_path, in_size=572, out_size=388):
    method __getitem__ (line 143) | def __getitem__(self, index):
    method __len__ (line 201) | def __len__(self):
  class SEMDataTest (line 206) | class SEMDataTest(Dataset):
    method __init__ (line 208) | def __init__(self, image_path, in_size=572, out_size=388):
    method __getitem__ (line 221) | def __getitem__(self, index):
    method __len__ (line 260) | def __len__(self):

FILE: src/mean_std.py
  function normalize_image (line 6) | def normalize_image(image):
  function find_mean (line 22) | def find_mean(image_path):
  function find_stdev (line 44) | def find_stdev(image_path):

FILE: src/modules.py
  function train_model (line 13) | def train_model(model, data_train, criterion, optimizer):
  function get_loss_train (line 34) | def get_loss_train(model, data_train, criterion):
  function validate_model (line 54) | def validate_model(model, data_val, criterion, epoch, make_prediction=Tr...
  function test_model (line 82) | def test_model(model_path, data_test, epoch, save_folder_name='predictio...
  function save_prediction_image (line 104) | def save_prediction_image(stacked_img, im_name, epoch, save_folder_name=...
  function polarize (line 126) | def polarize(img):

FILE: src/post_processing.py
  function postprocess (line 5) | def postprocess(image_path):

FILE: src/pre_processing.py
  function add_elastic_transform (line 7) | def add_elastic_transform(image, alpha, sigma, pad_size=30, seed=None):
  function flip (line 35) | def flip(image, option_value):
  function add_gaussian_noise (line 59) | def add_gaussian_noise(image, mean=0, std=1):
  function add_uniform_noise (line 75) | def add_uniform_noise(image, low=-10, high=10):
  function change_brightness (line 91) | def change_brightness(image, value):
  function ceil_floor_image (line 105) | def ceil_floor_image(image):
  function approximate_image (line 118) | def approximate_image(image):
  function normalization1 (line 131) | def normalization1(image, mean, std):
  function normalization2 (line 146) | def normalization2(image, max, min):
  function stride_size (line 158) | def stride_size(image_len, crop_num, crop_size):
  function multi_cropping (line 170) | def multi_cropping(image, crop_size, crop_num1, crop_num2):
  function cropping (line 221) | def cropping(image, crop_size, dim1, dim2):
  function add_padding (line 235) | def add_padding(image, in_size, out_size, mode):
  function division_array (line 250) | def division_array(crop_size, crop_num1, crop_num2, dim1, dim2):
  function image_concatenate (line 273) | def image_concatenate(image, crop_num1, crop_num2, dim1, dim2):

FILE: src/result_visualization.py
  function plotloss (line 16) | def plotloss(csvfile):

FILE: src/save_history.py
  function export_history (line 6) | def export_history(header, value, folder, file_name):
  function save_models (line 35) | def save_models(model, path, epoch):

FILE: src/simple_model.py
  class CleanU_Net (line 9) | class CleanU_Net(nn.Module):
    method __init__ (line 11) | def __init__(self):
    method forward (line 125) | def forward(self, x):
Condensed preview — 34 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (78K chars).
[
  {
    "path": ".gitignore",
    "chars": 1209,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*.csv\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / p"
  },
  {
    "path": "LICENSE",
    "chars": 1068,
    "preview": "MIT License\n\nCopyright (c) 2018 UGent Korea\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "README.md",
    "chars": 18764,
    "preview": "# pytorch-unet-segmentation\n\n**Members** : <a href=\"https://github.com/PyeongKim\">PyeongEun Kim</a>, <a href=\"https://gi"
  },
  {
    "path": "readme_images/description",
    "chars": 248,
    "preview": "z_original: original image\nbright_x: brightness increased by x\nelastic_x: different elastic \nflip_x: flip on x way\ngaus_"
  },
  {
    "path": "readme_images/file_name_description",
    "chars": 117,
    "preview": "file name explanation\n\np: padded image\nc: cropped image\nlb: left bottom\nlt: left top\nrb: right bottom\nrt: right top\n\n"
  },
  {
    "path": "src/accuracy.py",
    "chars": 2793,
    "preview": "#from post_processing import *\nimport numpy as np\nfrom PIL import Image\nimport glob as gl\nimport numpy as np\nfrom PIL im"
  },
  {
    "path": "src/advanced_model.py",
    "chars": 3888,
    "preview": "# full assembly of the sub-parts to form the complete net\nimport torch\nimport torch.nn as nn\nfrom torch.autograd import "
  },
  {
    "path": "src/dataset.py",
    "chars": 9592,
    "preview": "import numpy as np\nfrom PIL import Image\nimport glob\nimport torch\nimport torch.nn as nn\nfrom torch.autograd import Varia"
  },
  {
    "path": "src/main.py",
    "chars": 2899,
    "preview": "from advanced_model import CleanU_Net\nfrom dataset import *\nimport torch\nimport torch.nn as nn\nfrom torch.autograd impor"
  },
  {
    "path": "src/mean_std.py",
    "chars": 1753,
    "preview": "import numpy as np\nfrom PIL import Image\nimport glob\n\n\ndef normalize_image(image):\n    \"\"\"\n    Args:\n        image : a s"
  },
  {
    "path": "src/modules.py",
    "chars": 6444,
    "preview": "import numpy as np\nfrom PIL import Image\nimport torch\nimport torch.nn as nn\nfrom torch.autograd import Variable\nfrom dat"
  },
  {
    "path": "src/post_processing.py",
    "chars": 3406,
    "preview": "import numpy as np\nfrom matplotlib import pyplot as plt\n\n\ndef postprocess(image_path):\n    ''' postprocessing of the pre"
  },
  {
    "path": "src/pre_processing.py",
    "chars": 10612,
    "preview": "import numpy as np\nfrom scipy.ndimage.interpolation import map_coordinates\nfrom scipy.ndimage.filters import gaussian_fi"
  },
  {
    "path": "src/result_visualization.py",
    "chars": 2778,
    "preview": "\nimport matplotlib.pyplot as plt\nimport matplotlib as mpl\nimport pandas as pd\nimport numpy as np\n\n'''\nFor members who di"
  },
  {
    "path": "src/save_history.py",
    "chars": 1249,
    "preview": "import os\nimport csv\nimport torch\n\n\ndef export_history(header, value, folder, file_name):\n    \"\"\" export data to csv for"
  },
  {
    "path": "src/simple_model.py",
    "chars": 7330,
    "preview": "import torch\nimport torch.nn as nn\nfrom torch.autograd import Variable\nimport numpy as np\nfrom PIL import Image\nfrom tor"
  }
]

// ... and 18 more files (download for full content)

About this extraction

This page contains the full source code of the ugent-korea/pytorch-unet-segmentation GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 34 files (72.4 KB), approximately 19.9k tokens, and a symbol index with 58 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!