diff --git a/data.py b/data.py new file mode 100644 index 0000000000000000000000000000000000000000..ff4a8284480f124d0a6236114a6ff04aa2b0eb50 --- /dev/null +++ b/data.py @@ -0,0 +1,339 @@ +import os, pandas as pd, numpy as np, tensorflow as tf, math, random, matplotlib.pyplot as plt, sys, pickle, cv2 +from PIL import Image +from pdb import set_trace +from matplotlib import pyplot +from decimal import Decimal +from skimage.io import imshow + + +def getRandomImage(modelClass='cat'): # retrieves random image and label set + basePath = os.path.dirname(os.path.realpath(__file__)) + '/LINEMOD/' + modelClass + imageList = os.listdir(basePath + '/rgb/') + randNum = random.randrange(len(imageList)) + image = imageList[randNum] + with open(basePath + '/labels/' + os.listdir(basePath + '/labels/')[randNum]) as f: + labels = f.readline().split(' ')[1:19] + print(image) + image = filePathToArray(basePath + '/rgb/' + image) + # image = imread(basePath + image) + return image, labels + + +def getDataSplitImage(getValid, modelClass='cat'): # retrieves random image and label set from specified dataset + trainData, validData = getDataSplit(modelClass=modelClass) + basePath = os.path.dirname(os.path.realpath(__file__)) + '/LINEMOD/' + modelClass + if getValid: + choice = random.choice(validData) + with open(basePath + '/labels/' + choice[2]) as f: + labels = f.readline().split(' ')[1:19] + image = filePathToArray(basePath + '/rgb/' + choice[0]) + mask = filePathToArray(basePath + '/mask/' + choice[1]) + else: + choice = random.choice(trainData) + with open(basePath + '/labels/' + choice[2]) as f: + labels = f.readline().split(' ')[1:19] + image = filePathToArray(basePath + '/rgb/' + choice[0]) + mask = filePathToArray(basePath + '/mask/' + choice[1]) + return image, labels, mask, choice, validData + + +def getAllValData(modelClass='cat'): # retrieves random image and label set from specified dataset + trainData, validData = getDataSplit(modelClass=modelClass) + basePath = os.path.dirname(os.path.realpath(__file__)) + '/LINEMOD/' + modelClass + image_ls = [] + labels_ls = [] + mask_ls = [] + for choice in validData: + with open(basePath + '/labels/' + choice[2]) as f: + labels = f.readline().split(' ')[1:19] + labels_ls.append(labels) + image = filePathToArray(basePath + '/rgb/' + choice[0]) + mask = filePathToArray(basePath + '/mask/' + choice[1]) + image_ls.append(image) + mask_ls.append(mask) + return image_ls, labels_ls, mask_ls + + +def getMasterList(basePath): # returns list with image, mask, and label filenames + imageList = sorted(os.listdir(basePath + '/rgb/')) + maskList = sorted(os.listdir(basePath + '/mask/')) + labelList = sorted(os.listdir(basePath + '/labels/')) + if len(imageList) != len(maskList) or len(imageList) != len(labelList): + raise Exception("image, mask, and label list lengths do not match.") + + return [[a, b, c] for a, b, c in zip(imageList, maskList, labelList)] + + +def classTrainingGenerator(model, batchSize, masterList=None, height=480, width=640, augmentation=True, + **unused): # take input image, resize and store as rgb, create mask training data + basePath = os.path.dirname(os.path.realpath(__file__)) + '/LINEMOD/' + model + if masterList is None: + masterList = getMasterList(basePath) + random.shuffle(masterList) + i = 0 + while True: + xBatch = [] + yClassBatch = [] + for b in range(batchSize): + if i == len(masterList): + i = 0 + random.shuffle(masterList) + x = filePathToArray(basePath + '/rgb/' + masterList[i][0], height, width) + + yClassLabels = np.zeros((height, width, 1)) # 1 class confidence value per model + modelMask = filePathToArray(basePath + '/mask/' + masterList[i][1], height, width) + + if augmentation: + if random.choice([True, False]): # vertical flip + x = np.flipud(x) + modelMask = np.flipud(modelMask) + if random.choice([True, False]): # horizontal flip + x = np.fliplr(x) + modelMask = np.fliplr(modelMask) + + modelCoords = np.where(modelMask == 255)[:2] + + for modelCoord in zip(modelCoords[0][::3], modelCoords[1][::3]): + yClassLabels[modelCoord[0]][modelCoord[1]][0] = 1 + + xBatch.append(x) + yClassBatch.append(yClassLabels) + i += 1 + # print(np.array(yClassBatch).shape) + yield np.array(xBatch), np.array(yClassBatch) + + +def coordsTrainingGenerator(model, batchSize, masterList=None, height=480, width=640, augmentation=True, + altLabels=True): # takes input image and generates unit vector training data + + print(f"-------- {batchSize}----------") + basePath = os.path.dirname(os.path.realpath(__file__)) + '/LINEMOD/' + model + if masterList == None: + masterList = getMasterList(basePath) + random.shuffle(masterList) + i = 0 + while True: + xBatch = [] + yCoordBatch = [] + for b in range(batchSize): + if i == len(masterList): + i = 0 + random.shuffle(masterList) + x = filePathToArray(basePath + '/rgb/' + masterList[i][0], height, width) + + with open(basePath + ('/altLabels/' if altLabels else '/labels/') + masterList[i][2]) as f: + labels = f.readline().split(' ')[1:19] + + yCoordsLabels = np.zeros((height, width, 18)) # 9 coordinates + + modelMask = filePathToArray(basePath + '/mask/' + masterList[i][1], height, width) + + if augmentation: + if random.choice([True, False]): # vertical flip + x = np.flipud(x) + modelMask = np.flipud(modelMask) + for i in range(len(labels) // 2): + labels[i * 2 + 1] = str(round(1 - float(labels[i * 2 + 1]), 6)) + if random.choice([True, False]): # horizontal flip + x = np.fliplr(x) + modelMask = np.fliplr(modelMask) + for i in range(len(labels) // 2): + labels[i * 2] = str(round(1 - float(labels[i * 2]), 6)) + + modelCoords = np.where(modelMask == 255)[:2] + for modelCoord in zip(modelCoords[0][::3], modelCoords[1][::3]): + setTrainingPixel(yCoordsLabels, modelCoord[0], modelCoord[1], labels, height, width) + xBatch.append(x) + yCoordBatch.append(yCoordsLabels) + i += 1 + yield np.array(xBatch), np.array(yCoordBatch) + + +def combinedTrainingGenerator(model, batchSize, masterList=None, height=480, width=640, out0='activation_9', + out1='activation_10', augmentation=True, + altLabels=True): # take input image, resize and store as rgb, create training data + basePath = os.path.dirname(os.path.realpath(__file__)) + '/LINEMOD/' + model + if masterList is None: + masterList = getMasterList(basePath) + i = 0 + while True: + xBatch = [] + yCoordBatch = [] + yClassBatch = [] + for b in range(batchSize): + if i == len(masterList): + i = 0 + random.shuffle(masterList) + x = filePathToArray(basePath + '/rgb/' + masterList[i][0], height, width) + + with open(basePath + ('/altLabels/' if altLabels else '/labels/') + masterList[i][2]) as f: + labels = f.readline().split(' ')[1:19] + + yCoordsLabels = np.zeros((height, width, 18)) # 9 coordinates + yClassLabels = np.zeros((height, width, 1)) # 1 class confidence value per model + # yClassLabels = np.tile(np.array([1, 0]),(height, width, 1)) + + modelMask = filePathToArray(basePath + '/mask/' + masterList[i][1], height, width) + + if augmentation: + # for data aug, get random horizontal, vertical flips, flip input x with np, label vals = 1 - labelvals, flip mask + if random.choice([True, False]): # vertical flip + x = np.flipud(x) + modelMask = np.flipud(modelMask) + for i in range(len(labels) // 2): + labels[i * 2 + 1] = str(round(1 - float(labels[i * 2 + 1]), 6)) + if random.choice([True, False]): # horizontal flip + x = np.fliplr(x) + modelMask = np.fliplr(modelMask) + for i in range(len(labels) // 2): + labels[i * 2] = str(round(1 - float(labels[i * 2]), 6)) + + modelCoords = np.where(modelMask == 255)[:2] + for modelCoord in zip(modelCoords[0][::3], modelCoords[1][::3]): + setTrainingPixel(yCoordsLabels, modelCoord[0], modelCoord[1], labels, height, width) + yClassLabels[modelCoord[0]][modelCoord[1]][0] = 1 + xBatch.append(x) + yCoordBatch.append(yCoordsLabels) + yClassBatch.append(yClassLabels) + i += 1 + yield np.array(xBatch), {out0: np.array(yCoordBatch), out1: np.array(yClassBatch)} + + +def filePathToArray(filePath, height=480, width=640): # uses PIL Image object to return image as numpy array + image = Image.open(filePath) + image = image.resize((width, height)) + return np.array(image) + + +def showArrayAsImage(inArray, scaler=255, mode='F', saveImage=False): # displays image using PIL Image object + displayImage = inArray * scaler + displayImage = Image.fromarray(np.squeeze(displayImage), mode) + displayImage.show() + if saveImage: + displayImage = displayImage.convert("L") + displayImage.save("maskOutput.png", "png") + + +def setTrainingPixel(outImage, y, x, labels, height, width): + # for each pixel given, calculate unit vectors to keypoints and store on pixel in outImage object + for i in range(9): + yDiff = height * float(labels[i * 2 + 1]) - y # positive means y is above target in image + xDiff = width * float(labels[i * 2]) - x # positive means x is left of target in image + mag = math.sqrt(yDiff ** 2 + xDiff ** 2) + + outImage[y][x][i * 2 + 1] = yDiff / mag # assign unit vectors pointing from coordinate to keypoint + outImage[y][x][i * 2] = xDiff / mag + + +def showKeypoints(model='cat', batchSize=2, height=480, width=640): # display labelled keypoints on image + basePath = os.path.dirname(os.path.realpath(__file__)) + '/LINEMOD/' + model + masterList = getMasterList(basePath) + i = 0 + for b in range(batchSize): + if i == len(masterList): + i = 0 + random.shuffle(masterList) + print(masterList[i][0]) + x = filePathToArray(basePath + '/rgb/' + masterList[i][0], height, width) + + with open(basePath + '/labels/' + masterList[i][2]) as f: + labels = f.readline().split(' ')[1:19] + + yCoordsLabels = np.zeros((height, width, 18)) # 9 coordinates + + for ind in range(len(labels) // 2): + px = round(float(labels[ind * 2]) * width) + py = round(float(labels[ind * 2 + 1]) * height) + print("keypoint at " + str((px, py))) + temp = np.array(x[py][px]) + x[py][px] = np.array([0, 0, 0]) + plt.figure() + imshow(np.squeeze(x)) + plt.show() + x[py][px] = temp + i += 1 + + +def labelFloatsToPixels(floatList, height=480, width=640, decPlace=0): + # takes normalized pixel labels, converts to integer coordinates + labelList = [] + + for ind in range(len(floatList) // 2): + labelList.append([round(float(floatList[ind * 2]) * width, decPlace), + round(float(floatList[ind * 2 + 1]) * height, decPlace)]) # x, y format + + return labelList + + +def getDataSplit(genNew=False, split=.8, modelClass='cat'): + # access training data, get jpeg, mask, label filenames split into training / validation sets + if genNew: # create split + basePath = os.path.dirname(os.path.realpath(__file__)) + '/LINEMOD/' + modelClass + masterList = getMasterList(basePath) + random.shuffle(masterList) + + splitPoint = round(len(masterList) * split) + + splitDict = {"trainData": masterList[:splitPoint], "validData": masterList[splitPoint:]} + + with open("{0}_trainSplit".format(modelClass), 'wb') as f: + pickle.dump(splitDict, f) + + else: # load saved split + with open("{0}_trainSplit".format(modelClass), 'rb') as f: + splitDict = pickle.load(f) + return splitDict["trainData"], splitDict["validData"] + + +def genAltLabels(p3dOld, p3dNew, matrix=np.array([[572.4114, 0., 325.2611], [0., 573.57043, 242.04899], [0., 0., 1.]]), + method=cv2.SOLVEPNP_ITERATIVE, modelClass='cat', height=480, width=640, + showPoint=False): # generate pixel labels for p3dNew using labels for p3dOld + + p3dOld = np.ascontiguousarray(p3dOld.astype(np.float64)) + p3dOld = np.append([[0, 0, 0]], p3dOld, 0) + + labelDict = {'ape': 0, 'benchvise': 1, 'cam': 2, 'can': 3, 'cat': 4, 'driller': 5, 'duck': 6, 'eggbox': 7, + 'glue': 8, 'holepuncher': 9, 'iron': 10, 'lamp': 11, 'phone': 12} + basePath = os.path.dirname(os.path.realpath(__file__)) + '/LINEMOD/' + modelClass + masterList = getMasterList(basePath) + + labelPath = basePath + '/labels/' + newLabelPath = basePath + '/altLabels/' + for el in masterList: + with open(labelPath + el[2], 'r') as f: + labels = f.readline().split(' ')[1:19] # ignore class label and centroid + + labels = [float(el) for el in labels] + labels = np.reshape(labels, (p3dOld.shape[0], 2)) + labels = np.array([[el[0] * width, el[1] * height] for el in labels]) + + p2d = np.ascontiguousarray(labels.astype(np.float64)) + + _, R_exp, tVec = cv2.solvePnP(p3dOld, p2d, matrix, np.zeros(shape=[8, 1], dtype='float64'), flags=method) + + (plotPoints, jacobian) = cv2.projectPoints(p3dNew, R_exp, tVec, matrix, np.zeros(shape=[8, 1], dtype='float64')) + + print(plotPoints) + + image = filePathToArray(basePath + '/rgb/' + el[0]) + + # print("looking at {0}".format(el[0])) + + newLabels = [labelDict[modelClass]] + for coord in plotPoints: + if showPoint: + px = int(round(coord[0][0])) + py = int(round(coord[0][1])) + print("keypoint at " + str((px, py))) + temp = np.array(image[py][px]) + image[py][px] = np.array([0, 0, 0]) + plt.figure() + imshow(np.squeeze(image)) + plt.show() + image[py][px] = temp + newLabels.append(coord[0][0] / width) + newLabels.append(coord[0][1] / height) + + with open(newLabelPath + el[2], 'w') as f: + for lab in newLabels: + f.write(str(lab) + ' ')