Commit 042b2d9a authored by josh's avatar josh

putting together ml pipline

parent 0a3ac6ca
__pycache__/
modules/__pycache__/
\ No newline at end of file
{
"cells": [],
"metadata": {},
"cells": [
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"from modules.ai4hdrModel import *\n",
"\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"PosixPath('/home/josh/projects/suli_fall2021/ai4hdr_backend/roadTest')"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sampleDir = Path.cwd().joinpath(\"roadTest\")\n",
"sampleDir"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(10, 128, 128, 3)\n",
"(10, 128, 128)\n"
]
}
],
"source": [
"(xSamples, ySamples) = getSamples(sampleDir)\n",
"print(xSamples.shape)\n",
"print(ySamples.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# "
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"X TRAIN SHAPE: (5, 128, 128, 3)\n",
"Y TRAIN SHAPE: (5, 128, 128)\n",
"X TEST SHAPE: (5, 128, 128, 3)\n",
"Y TEST SHAPE: (5, 128, 128)\n"
]
}
],
"source": [
"xTrain = xSamples[0:5,:,:,:]\n",
"yTrain = ySamples[0:5,:,:]\n",
"print(\"X TRAIN SHAPE:\", xTrain.shape)\n",
"print(\"Y TRAIN SHAPE:\", yTrain.shape)\n",
"\n",
"xTest = xSamples[5:10,:,:,:]\n",
"yTest = ySamples[5:10,:,:]\n",
"print(\"X TEST SHAPE:\", xTest.shape)\n",
"print(\"Y TEST SHAPE:\", yTest.shape)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "gpu_tf",
"language": "python",
"name": "gpu_tf"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.9"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
from ai4hdr_backend.Scripts.ai4hdr_utils import importAndProcess
\ No newline at end of file
from ai4hdr_backend.lib.ai4hdr import importAndProcess
\ No newline at end of file
......@@ -12,7 +12,7 @@ from sklearn.cluster import MeanShift, estimate_bandwidth
from skimage import color
def sliceImage( imgArr: np.array, newSize: tuple ) -> dict:
def sliceImage(imgArr: np.array, newSize: tuple) -> dict:
'''
Creates slices of an image.
......@@ -22,7 +22,7 @@ def sliceImage( imgArr: np.array, newSize: tuple ) -> dict:
returns: dictionary containing the following information
{
"slicedImages": [ ( xStartPos, yStartPos, slicedImgArr ) ],
"slicedImages": [ (xStartPos, yStartPos, slicedImgArr) ],
"sliceCount" : int
}
OR empty dictionary if slicing was unable to be completed
......@@ -41,16 +41,16 @@ def sliceImage( imgArr: np.array, newSize: tuple ) -> dict:
imageList = []
# Process image
for i in range( 0, width, newWidth ):
for j in range( 0, height, newHeight ):
for i in range(0, width, newWidth):
for j in range(0, height, newHeight):
newSliceCount += 1
# Create array of zeros of slice size
base = np.zeros( ( newWidth, newHeight, imgArr.shape[2] ) )
base = np.zeros((newWidth, newHeight, imgArr.shape[2]))
# Slice image and broadcase to base array
# Slice will be blacked out when outside range of original image
sliceArr = imgArr[i:i+newWidth, j:j+newHeight, :]
base[ :sliceArr.shape[0], :sliceArr.shape[1]] = sliceArr
imageList.append( ( i, j, base ) )
imageList.append((i, j, base))
return {
"slicedImages": imageList,
......@@ -58,7 +58,7 @@ def sliceImage( imgArr: np.array, newSize: tuple ) -> dict:
}
def meanShiftSegmentation( imgArr: np.array, spatialRadius: int=6, rangeRadius: int=6, minDensity: int=50 ) -> tuple:
def meanShiftSegmentation(imgArr: np.array, spatialRadius: int=6, rangeRadius: int=6, minDensity: int=50) -> tuple:
'''
SOURCE - https://github.com/fjean/pymeanshift
......@@ -68,33 +68,33 @@ def meanShiftSegmentation( imgArr: np.array, spatialRadius: int=6, rangeRadius:
- rangeRadius : range radius for ms algo
- minDensity : min density for ms algo
return: ( segmented_image, labels_image, number_regions )
return: (segmented_image, labels_image, number_regions)
'''
return pms.segment( imgArr,
return pms.segment(imgArr,
spatial_radius=spatialRadius,
range_radius=rangeRadius,
min_density=minDensity )
min_density=minDensity)
# TO DO::POTENTIAL PROBLEM - this function holds all the results in memory, may be too much for large images
# consider option to do limited what is produced
def sliceAndMeanShift( imgArr: np.array ):
def sliceAndMeanShift(imgArr: np.array):
'''
Returns dictionary:
{
"slices":
{
"128": [ ( x, y, imgArr ) ], <- x, y are pixel start positions in original image
"128": [ (x, y, imgArr) ], <- x, y are pixel start positions in original image
"256": ...,
"512":
},
"meanShift":
{
"128": [ ( x, y, numRegions, segImage, labelImage ) ],
"128": [ (x, y, numRegions, segImage, labelImage) ],
"256": ...,
"512":
}
......@@ -120,26 +120,26 @@ def sliceAndMeanShift( imgArr: np.array ):
sizes = [ 128, 256, 512 ]
# Loop: 128, 256, 512
for size in sizes:
print( "Processing Size:", size )
print("Processing Size:", size)
if imgArr.shape[0] >= size and imgArr.shape[1] >= size:
# Step 4: Slice
sliceResults = sliceImage( imgArr, ( size, size ) )
sliceResults = sliceImage(imgArr, (size, size))
# Step 5: Save slices
finalResults["slices"][str( size )] = sliceResults["slicedImages"]
finalResults["slices"][str(size)] = sliceResults["slicedImages"]
# Step 6: Mean Shift on all slices
for res in sliceResults["slicedImages"]:
i = res[0]
j = res[1]
slicedImg = res[2].astype( np.uint8 )
#print( slicedImg.shape )
slicedImg = res[2].astype(np.uint8)
#print(slicedImg.shape)
# mean shift
( segmentedImage, labelsImage, numberRegions ) = meanShiftSegmentation( slicedImg )
(segmentedImage, labelsImage, numberRegions) = meanShiftSegmentation(slicedImg)
# add to results
finalResults["meanShift"][str( size )].append( ( i, j, numberRegions, segmentedImage, labelsImage ) )
finalResults["meanShift"][str(size)].append((i, j, numberRegions, segmentedImage, labelsImage))
return finalResults
......@@ -162,126 +162,126 @@ Database file structure example:
| | | | |--512x512
'''
def initDB( dbLoc: str, name: str ) -> bool:
def initDB(dbLoc: str, name: str) -> bool:
'''
Initialized the image database at a given directory
File Struture:
|-- ImageDatabase
│   |-- Data
'''
dbLoc = pathlib.Path( dbLoc )
dbDir = dbLoc.joinpath( name )
dbLoc = pathlib.Path(dbLoc)
dbDir = dbLoc.joinpath(name)
if dbDir.is_dir():
return False
else:
imagesDir = dbDir.joinpath( "Images" )
os.mkdir( dbDir )
os.mkdir( imagesDir )
imagesDir = dbDir.joinpath("Images")
os.mkdir(dbDir)
os.mkdir(imagesDir)
return True
def importAndProcess( imgPath: str, dbPath: str, newImgName: str ):
def importAndProcess(imgPath: str, dbPath: str, newImgName: str):
'''
Slices and segments an image and imports it into the database
'''
imgPath = pathlib.Path( imgPath )#.absolute()
dbPath = pathlib.Path( dbPath )#.absolute()
imgPath = pathlib.Path(imgPath)#.absolute()
dbPath = pathlib.Path(dbPath)#.absolute()
# Ensure database exists
if not dbPath.is_dir():
print( "ERROR: No database exists at {}".format( dbPath ) )
print("ERROR: No database exists at {}".format(dbPath))
return False
# Internal database directory
imagesPath = dbPath.joinpath( "Images" )
imagesPath = dbPath.joinpath("Images")
# Ensure database was initialized correctly
if not imagesPath.is_dir():
print( "ERROR - Database Not Initialized: Use 'initDB.py' to init database.")
print("ERROR - Database Not Initialized: Use 'initDB.py' to init database.")
return False
# PROCESS IMAGE
# Step 1: Read in image
imgArr = cv2.imread( str( imgPath ) )
fileExt = imgPath.name.split( "." )[-1]
imgArr = cv2.imread(str(imgPath))
fileExt = imgPath.name.split(".")[-1]
# Auto increment id
dbIDs = [int( f.name.split( "-" )[0] ) for f in imagesPath.iterdir() ]
dbIDs = [int(f.name.split("-")[0]) for f in imagesPath.iterdir() ]
dbID = 0
if len( dbIDs ) != 0:
dbID = max( dbIDs ) + 1
if len(dbIDs) != 0:
dbID = max(dbIDs) + 1
# Create dir for image
baseImagePath = imagesPath.joinpath( "{}-{}-{}-OR".format( dbID, fileExt, newImgName ) )
baseImagePath = imagesPath.joinpath("{}-{}-{}-OR".format(dbID, fileExt, newImgName))
baseImageName = baseImagePath.name
os.mkdir( baseImagePath )
os.mkdir(baseImagePath)
# Step 2: Save Original File
baseImageFilePath = baseImagePath.joinpath( "{}.{}".format( baseImageName, fileExt ) )
cv2.imwrite( str( baseImageFilePath ), imgArr )
baseImageFilePath = baseImagePath.joinpath("{}.{}".format(baseImageName, fileExt))
cv2.imwrite(str(baseImageFilePath), imgArr)
# Create dir for sliced images
slicedImagePath = baseImagePath.joinpath( "SL" )
os.mkdir( slicedImagePath )
slicedImagePath = baseImagePath.joinpath("SL")
os.mkdir(slicedImagePath)
# Run processing
processedResult = sliceAndMeanShift( imgArr )
processedResult = sliceAndMeanShift(imgArr)
# Save Slices
sizes = [ "128", "256", "512" ]
for size in sizes:
slicedSizePath = slicedImagePath.joinpath( size )
os.mkdir( slicedSizePath )
slicedSizePath = slicedImagePath.joinpath(size)
os.mkdir(slicedSizePath)
# Slices and corresponding processed images
sliceList = processedResult["slices"][size]
processedList = processedResult["meanShift"][size]
for i in range( len( sliceList ) ):
for i in range(len(sliceList)):
# <autoInc>-<imgExt>-<name>-128-xPix-yPix
x = sliceList[i][0]
y = sliceList[i][1]
sliceArr = sliceList[i][2]
sliceBaseName = "{}-{}-{}-{}-SL".format( baseImageName, size, x, y )
sliceBasePath = slicedSizePath.joinpath( sliceBaseName )
os.mkdir( sliceBasePath )
sliceBaseName = "{}-{}-{}-{}-SL".format(baseImageName, size, x, y)
sliceBasePath = slicedSizePath.joinpath(sliceBaseName)
os.mkdir(sliceBasePath)
# Save Sliced Image
sliceFilePath = sliceBasePath.joinpath( "{}.{}".format( sliceBaseName, fileExt ) )
cv2.imwrite( str( sliceFilePath ), sliceArr )
sliceFilePath = sliceBasePath.joinpath("{}.{}".format(sliceBaseName, fileExt))
cv2.imwrite(str(sliceFilePath), sliceArr)
# Create Processed Slice Path
sliceProcPath = sliceBasePath.joinpath( "PROC" )
os.mkdir( sliceProcPath )
sliceProcPath = sliceBasePath.joinpath("PROC")
os.mkdir(sliceProcPath)
# Segmented image and label image
msSegArr = processedList[i][3]
msLabImg = processedList[i][4]
msSegDir = sliceProcPath.joinpath( "{}-{}-{}".format( sliceBaseName,
msSegDir = sliceProcPath.joinpath("{}-{}-{}".format(sliceBaseName,
"MSSEG",
"PROC" ) )
msSegFileDir = msSegDir.joinpath( "{}.{}".format( msSegDir.name, fileExt ) )
"PROC"))
msSegFileDir = msSegDir.joinpath("{}.{}".format(msSegDir.name, fileExt))
msLabFileDir = msSegDir.joinpath( "{}-{}-{}".format( sliceBaseName,
msLabFileDir = msSegDir.joinpath("{}-{}-{}".format(sliceBaseName,
"MSLAB",
"PROC" ) )
"PROC"))
os.mkdir( msSegDir )
os.mkdir(msSegDir)
# Save processed image and label array
cv2.imwrite( str( msSegFileDir ), msSegArr )
np.save( str( msLabFileDir ), msLabImg )
cv2.imwrite(str(msSegFileDir), msSegArr)
np.save(str(msLabFileDir), msLabImg)
'''
OTHER IMPLEMENTATIONS
'''
def meanshift3Channel( imagePath: str, outPath: str, quantile=0.2, samples=500, classColors: list=None ) -> dict:
def meanshift3Channel(imagePath: str, outPath: str, quantile=0.2, samples=500, classColors: list=None) -> dict:
'''
SOURCE: https://www.efavdb.com/mean-shift
......@@ -290,7 +290,7 @@ def meanshift3Channel( imagePath: str, outPath: str, quantile=0.2, samples=500,
Arguments:
- imagePath : path to image used
- outPath : path to save segmented image ( image type extension automatically added )
- outPath : path to save segmented image (image type extension automatically added)
- quantile : used for estimate_bandwidth function, should be between [0, 1], default: 0.2
- samples : used for estimate_bandwidth function, number of samples to use, defualt: 500
- classColors : custom list of colors to use for classes, default: [ "darkgreen", "indigo", "gold" ]
......@@ -298,9 +298,9 @@ def meanshift3Channel( imagePath: str, outPath: str, quantile=0.2, samples=500,
Returns: a dictionary mapping the class integer to a tuple containing a color name and rgb value
{
0: ( "darkgreen", ( 0.0, 0.3, 0.0 ) ),
1: ( "indigo", ( 0.2, 0.0, 0.5 ) ),
2: ( "gold", ( 1.0, 0.8, 0.0 ) )
0: ("darkgreen", (0.0, 0.3, 0.0)),
1: ("indigo", (0.2, 0.0, 0.5)),
2: ("gold", (1.0, 0.8, 0.0))
}
Quantile and samples are used for sklearn estimate_bandwidth function.
......@@ -310,48 +310,48 @@ def meanshift3Channel( imagePath: str, outPath: str, quantile=0.2, samples=500,
classColors = [ "darkgreen", "indigo", "gold" ]
# create mapping for color name to rgb
color1 = to_rgb( classColors[0] )
color2 = to_rgb( classColors[1] )
color3 = to_rgb( classColors[2] )
color1 = to_rgb(classColors[0])
color2 = to_rgb(classColors[1])
color3 = to_rgb(classColors[2])
# cv2 uses BGR order, flip for RGB
colorToBGR = {
classColors[0]: ( color1[2], color1[1], color1[0] ),
classColors[1]: ( color2[2], color2[1], color2[0] ),
classColors[2]: ( color3[2], color3[1], color3[0] ),
classColors[0]: (color1[2], color1[1], color1[0]),
classColors[1]: (color2[2], color2[1], color2[0]),
classColors[2]: (color3[2], color3[1], color3[0]),
}
fileExt = pathlib.Path( imagePath ).name.split( "." )[-1]
fileExt = pathlib.Path(imagePath).name.split(".")[-1]
# read image and generate feature arrays
img = cv2.imread( imagePath )
imgArr = np.array( img )
flatArr = np.reshape( imgArr, [-1, 3] )
img = cv2.imread(imagePath)
imgArr = np.array(img)
flatArr = np.reshape(imgArr, [-1, 3])
# run mean shift
bandwidth = estimate_bandwidth( X=flatArr, quantile=quantile, n_samples=samples )
meanShift = MeanShift( bandwidth, bin_seeding=True, n_jobs=-1 ) # n_jobs=-1 uses all processors
meanShift.fit( flatArr )
bandwidth = estimate_bandwidth(X=flatArr, quantile=quantile, n_samples=samples)
meanShift = MeanShift(bandwidth, bin_seeding=True, n_jobs=-1) # n_jobs=-1 uses all processors
meanShift.fit(flatArr)
# use labels to construct a class array with classes: 0, 1, 2
labels = meanShift.labels_
classArr = np.reshape( labels, [img.shape[0], img.shape[1]] )
classArr = np.reshape(labels, [img.shape[0], img.shape[1]])
# use classColors to generate a 3 channel image from class array
rgbValues = []
for i in range( classArr.shape[0] ):
for j in range( classArr.shape[1] ):
for i in range(classArr.shape[0]):
for j in range(classArr.shape[1]):
color = classColors[classArr[i][j]]
rgbValues.append( colorToBGR[color] )
finalArr = np.asarray( rgbValues )
finalArr = np.reshape( finalArr, imgArr.shape )
rgbValues.append(colorToBGR[color])
finalArr = np.asarray(rgbValues)
finalArr = np.reshape(finalArr, imgArr.shape)
# scale values to range [0, 255] to save with opencv
finalArr *= 255.0
cv2.imwrite( "{}.{}".format( outPath, fileExt ), finalArr )
cv2.imwrite("{}.{}".format(outPath, fileExt), finalArr)
return {
0: ( classColors[0], color1 ),
1: ( classColors[1], color2 ),
2: ( classColors[2], color3 )
0: (classColors[0], color1),
1: (classColors[1], color2),
2: (classColors[2], color3)
}
import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path
from PIL import Image
import tensorflow as tf
from tensorflow.keras.layers import Input, Conv2D
from tensorflow.keras.models import Model
from tensorflow.keras.applications.vgg16 import VGG16
from sklearn.ensemble import RandomForestClassifier
class HDRModel:
def __init__(self, modelShape):
self.featureModel = None
self.rfClassifer = None
self.inputChannels = 3
self.outputChannels = 1
self.__initModels(modelShape)
def fit(self, xTrain, yTrain):
# Get features from VGG16 built model
features = self.__getFeatures(xTrain)
# Reshape input for random forest
xForestTrain = features.reshape(-1, features.shape[-1])
yForestTrain = yTrain.reshape(-1)
print("Forest Train X:", xForestTrain.shape)
print("Forest Train Y:", yForestTrain.shape)
self.rfClassifer.fit(xForestTrain, yForestTrain)
def predict(self, xInput):
'''
Supports only a single input: shape=(x, y, z)
'''
print("X INPUT", xInput.shape)
plt.imshow(xInput)
plt.show()
# Extract features from input
xExpand = np.expand_dims(xInput, axis=0)
features = self.__getFeatures(xExpand)
# Reshape input for random forest
forestInput = features.reshape(-1, features.shape[-1])
print("FOREST INPUT", forestInput.shape)