Switch to side-by-side view

--- a
+++ b/Projects/Augmentation/Classes/Data.py
@@ -0,0 +1,250 @@
+############################################################################################
+#
+# Project:       Peter Moss Acute Myeloid & Lymphoblastic Leukemia AI Research Project
+# Repository:    ALL Detection System 2019
+# Project:       Data Augmentation
+#
+# Author:        Adam Milton-Barker (AdamMiltonBarker.com)
+# Contributors:
+# Title:         Data Class
+# Description:   Data augmentation class for the ALL Detection System 2019.
+# License:       MIT License
+# Credit:        Based on methods outline in the Leukemia Blood Cell Image
+#                Classification Using Convolutional Neural Network paper:
+#                http://www.ijcte.org/vol10/1198-H0012.pdf
+# Last Modified: 2020-07-14
+#
+############################################################################################
+
+import os
+import cv2
+import random
+import time
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+from numpy.random import seed
+from scipy import ndimage
+from PIL import Image
+
+from Classes.Helpers import Helpers
+
+
+class Data():
+    """ ALL Detection System 2019 Data Class
+
+    Data augmentation class for the ALL Detection System 2019 Data Augmentation project.
+    """
+
+    def __init__(self):
+        """ Initializes the Data class. """
+
+        self.Helpers = Helpers()
+        self.confs = self.Helpers.loadConfs()
+        self.fixed = tuple(
+            (self.confs["Settings"]["ImgDims"], self.confs["Settings"]["ImgDims"]))
+
+        self.filesMade = 0
+        self.trainingDir = self.confs["Settings"]["TrainDir"]
+
+        self.seed = self.confs["Settings"]["Seed"]
+        seed(self.seed)
+
+    def writeImage(self, filename, image):
+        """ Writes an image to provided file path. """
+
+        if filename is None:
+            print("Filename does not exist, file cannot be written.")
+            return
+
+        if image is None:
+            print("Image does not exist, file cannot be written.")
+            return
+
+        try:
+            cv2.imwrite(filename, image)
+        except:
+            print("File was not written! " + filename)
+
+    def resize(self, filePath, savePath, show=False):
+        """ Writes a resized image to provided file path. """
+
+        image = cv2.resize(cv2.imread(filePath), self.fixed)
+        self.writeImage(savePath, image)
+        self.filesMade += 1
+        print("Resized image written to: " + savePath)
+
+        if show is True:
+            plt.imshow(image)
+            plt.show()
+
+        return image
+
+    def grayScale(self, image, grayPath, show=False):
+        """ Writes a grayscaled image to provided file path. """
+
+        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
+        self.writeImage(grayPath, gray)
+        self.filesMade += 1
+        print("Grayscaled image written to: " + grayPath)
+
+        if show is True:
+            plt.imshow(gray)
+            plt.show()
+
+        return image, gray
+
+    def equalizeHist(self, gray, histPath, show=False):
+        """ Writes a histogram equalized image to provided file path. """
+
+        hist = cv2.equalizeHist(gray)
+        self.writeImage(histPath, cv2.equalizeHist(gray))
+        self.filesMade += 1
+        print("Histogram equalized image written to: " + histPath)
+
+        if show is True:
+            plt.imshow(hist)
+            plt.show()
+
+        return hist
+
+    def reflection(self, image, horPath, verPath, show=False):
+        """ Writes a reflected image to provided file path. """
+
+        horImg = cv2.flip(image, 0)
+        self.writeImage(horPath, horImg)
+        self.filesMade += 1
+        print("Horizontally reflected image written to: " + horPath)
+
+        if show is True:
+            plt.imshow(horImg)
+            plt.show()
+
+        verImg = cv2.flip(image, 1)
+        self.writeImage(verPath, verImg)
+        self.filesMade += 1
+        print("Vertical reflected image written to: " + verPath)
+
+        if show is True:
+            plt.imshow(verImg)
+            plt.show()
+
+        return horImg, verImg
+
+    def gaussian(self, filePath, gaussianPath, show=False):
+        """ Writes a gaussian blurred image to provided file path. """
+
+        gaussianBlur = ndimage.gaussian_filter(
+            plt.imread(filePath), sigma=5.11)
+        self.writeImage(gaussianPath, gaussianBlur)
+        self.filesMade += 1
+        print("Gaussian image written to: " + gaussianPath)
+
+        if show is True:
+            plt.imshow(gaussianBlur)
+            plt.show()
+        return gaussianBlur
+
+    def translate(self, image, filePath, show=False):
+        """
+        Writes transformed copy of the image to the filepath provided. 
+        """
+
+        cols, rows, chs = image.shape
+
+        translated = cv2.warpAffine(image, np.float32([[1, 0, 84], [0, 1, 56]]), (rows, cols),
+                                    borderMode=cv2.BORDER_CONSTANT, borderValue=(144, 159, 162))
+
+        self.writeImage(filePath, translated)
+        self.filesMade += 1
+        print("Translated image written to: " + filePath)
+
+        if show is True:
+            plt.imshow(translated)
+            plt.show()
+
+        return translated
+
+    def rotation(self, path, filePath, filename, show=False):
+        """
+        Writes rotated copies of the image to the filepath provided. 
+        """
+
+        img = Image.open(filePath)
+
+        image = cv2.imread(filePath)
+        cols, rows, chs = image.shape
+
+        for i in range(0, 20):
+            # Seed needs to be set each time randint is called
+            random.seed(self.seed)
+            randDeg = random.randint(-180, 180)
+            matrix = cv2.getRotationMatrix2D((cols/2, rows/2), randDeg, 0.70)
+            rotated = cv2.warpAffine(image, matrix, (rows, cols), borderMode=cv2.BORDER_CONSTANT,
+                                     borderValue=(144, 159, 162))
+            fullPath = os.path.join(
+                path, str(randDeg) + '-' + str(i) + '-' + filename)
+
+            self.writeImage(fullPath, rotated)
+            self.filesMade += 1
+            print("Rotated image written to: " + fullPath)
+
+            if show is True:
+                plt.imshow(rotated)
+                plt.show()
+
+    def processDataset(self):
+        """ Processes the dataset. """
+
+        for directory in os.listdir(self.trainingDir):
+
+            # Skip none data directories
+            if(directory == ".ipynb_checkpoints" or directory == "__pycache__"):
+                continue
+
+            self.filesMade = 0
+
+            path = os.path.join(self.confs["Settings"]["TrainDir"], directory)
+            sortedPath = os.path.join(
+                self.confs["Settings"]["AugDir"], directory)
+
+            # Stops program from crashing if augmented folders do not exist
+            if not os.path.exists(sortedPath):
+                os.makedirs(sortedPath)
+
+            if os.path.isdir(path):
+                fCount = 0
+                for filename in os.listdir(path):
+                    if filename.endswith('.jpg'):
+
+                        filePath = os.path.join(path, filename)
+                        fullPath = sortedPath + "/" + filename
+
+                        image = self.resize(filePath, fullPath, False)
+                        image, gray = self.grayScale(image, os.path.join(
+                                                     sortedPath, "Gray-" + filename), False)
+
+                        hist = self.equalizeHist(gray, os.path.join(
+                                                 sortedPath, "Hist-" + filename), False)
+
+                        horImg, verImg = self.reflection(image, os.path.join(sortedPath, "Hor-" + filename),
+                                                         os.path.join(sortedPath, "Ver-" + filename), False)
+
+                        gaussianBlur = self.gaussian(filePath, os.path.join(
+                                                     sortedPath, "Gaus-" + filename), False)
+
+                        translated = self.translate(image, os.path.join(
+                            sortedPath, "Trans-"+filename), False)
+
+                        self.rotation(sortedPath, fullPath, filename)
+                        fCount += 1
+                        print("Total augmented files created so far " +
+                              str(self.filesMade))
+                        print("")
+                    else:
+                        continue
+
+                print(" AML/ALL Augmentation: " + self.Helpers.currentDateTime() + "  - Added filters to " + str(fCount) +
+                      " files in the " + str(directory) + " directory, with a total of " + str(self.filesMade) + " augmented files created.")
+                print("")