def dice_coefficient(ground_truth, prediction, threshold=127): ground_truth = moil.getBinaryThreshold(ground_truth, threshold) prediction = moil.getBinaryThreshold(prediction, threshold) intersection = np.logical_and(ground_truth, prediction) union = np.logical_or(ground_truth, prediction) dice = (2 * np.sum(intersection)) / (np.sum(intersection) + np.sum(union)) print("Dice Sorensen: " + str(dice)) return dice
def jaccard_index(ground_truth, prediction, threshold=127): ground_truth = moil.getBinaryThreshold(ground_truth, threshold) prediction = moil.getBinaryThreshold(prediction, threshold) intersection = np.logical_and(ground_truth, prediction) union = np.logical_or(ground_truth, prediction) jaccard = np.sum(intersection) / np.sum(union) print("Jaccard Index: " + str(jaccard)) return jaccard
def predict(self, im): w, h, c = moil.getWidthHeightChannels(im) if w != self.colDim or h != self.rowDim or c != self.channels: im = cv2.resize(im, (self.colDim, self.rowDim))[:, :] im = self.prepareImage(im) im = self.model.predict(im) im = moil.convertImageNetOutput(im) return im
def AtrophyPrediction(self, roi): img = self.ModAtrophy.predict(roi) atrophyRate = met.atrophyRate(img) w, h, c = moil.getWidthHeightChannels(self.currentImg) img = cv2.resize(img, (round(160 * w / 600), round(160 * (w * 0.75) / 450))) img = moil.getBinaryThreshold(img) return atrophyRate, img
def draw(pred, toDraw, morph_iter=0, threshold=127, thickness=2): thresh = moil.getBinaryThreshold(pred, threshold) closed = moil.morphMultiClosing(thresh, morph_iter) contour = moil.selectBiggerCircularContour(closed) if toDraw is not None and contour is not None: cv2.drawContours(toDraw, [contour], -1, (0, 0, 255), thickness)
def binaryDiff(pred, true, threshold=127, globalCount=False): thresh = moil.getBinaryThreshold(pred, threshold) threshTrue = moil.getBinaryThreshold(true, threshold) unique, counts = np.unique(threshTrue, return_counts=True) trueC = dict(zip(unique, counts)) diff = np.int16(threshTrue) - np.int16(thresh) unique, counts = np.unique(diff, return_counts=True) diffC = dict(zip(unique, counts)) try: Negatives = trueC[0] except: Negatives = 0 try: Positives = trueC[255] except: Positives = 0 try: FN = diffC[255] except: FN = 0 try: FP = diffC[-255] except: FP = 0 TP = Positives - FN TN = Negatives - FP try: Specifity = TN / Negatives except: Specifity = 1 try: Sensitivity = TP / Positives except: Sensitivity = 1 Accuracy = (TP + TN) / (Positives + Negatives) Jouden = Sensitivity + Specifity - 1 print("Youden Index: " + str(Jouden) + ", Sensivity: " + str(Sensitivity) + ", Specifity: " + str( Specifity) + ", Accuracy: " + str(Accuracy) ) if globalCount: return [TP, FN, FP, TN] return Jouden
def Merge(self, im): h, w = np.shape(im) merged = np.zeros((h, w, 3)) lbp = self.LBP.describe(im) grad = self.Grad.getGradientSum(im) if self.equalize: im = cv2.equalizeHist(im) lbp = cv2.equalizeHist(lbp) grad = cv2.equalizeHist(grad) if self.testMode: moil.show(im, other_im=[lbp, grad]) merged[:, :, 0] = im merged[:, :, 1] = lbp merged[:, :, 2] = grad return merged.astype('uint8')
def createExitModel(ModelName, gray=True, preprocessFunc=lambda x: x): FeatureName = "Wyjscie" TrainModeName = FeatureName + ModelName image_size_level = 5 base_scale = 1.0 cols, rows = moil.getColsRows(level=image_size_level, base_scale=base_scale) if (gray): mode = 0 channels_in = 1 color_mode = 'grayscale' else: mode = 1 channels_in = 3 color_mode = 'rgb' filters = 8 weights_path = "../../weights/unet" + TrainModeName var_filename = "../../weights/var" + TrainModeName + ".txt" Mod = md.Models(rows, cols, mode=mode, channels=channels_in, weights_path=weights_path, var_filename=var_filename, read_func=moil.read_and_size, preprocessFunc=preprocessFunc) Mod.get_model(filters=filters) Mod.load_weights() return Mod
def atrophyRate(img, threshold = 127): img = moil.getBinaryThreshold(img, threshold) unique, counts = np.unique(img, return_counts=True) try: count = dict(zip(unique, counts))[255] except: count = 0 return count / 20576
def square_circle_on_1_2_in_path(path): for i in range(6): im, im_cp = moil.read_and_size_with_copy(str(i), path=path, scale=0.2) im = equalize_border_with_mean_or_val(im) h, w = np.shape(im) r = (int)(h / 8) img_sqd = square_circle_difference_filter_2d(im, r) # img_sqd = square_circle_minus_filter_2d(im, r) # img_sqd = circle_filter_2d(im) img_sqd = cv2.equalizeHist(img_sqd) ret, imt = cv2.threshold(img_sqd, 250, 255, cv2.THRESH_BINARY) cv2.imshow('win2', im_cp) cv2.imshow('win32', img_sqd) moil.show(imt) '''imt2,cnt, hier = cv2.findContours(imt, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
def registerImageCsv(repo_path, image_path, image_name, image, function): patient, date, eye = morn.getPatientDateEye(image_path) width, height, channels = moil.getWidthHeightChannels(image) func_name = function.__name__ header = [ 'patient', 'date', 'eye', 'name', 'width', 'height', 'channels', 'function' ] row = [patient, date, eye, image_name, width, height, channels, func_name] writeToCsv(repo_path + "imageData.csv", header, row)
def __init__(self, image_path, winname, size_level, scale): self.image_path = image_path self.winname = winname self.accepted = True self.masks_done = 0 self.mask = None self.rr = 0 self.xx = 0 self.yy = 0 self.targetSize = moil.getColsRows(size_level, scale)
def getCenter(pred, widthRef, heightRef, morph_iter=0, threshold=127): thresh = moil.getBinaryThreshold(pred, threshold) closed = moil.morphMultiClosing(thresh, morph_iter) contour = moil.selectBiggerCircularContour(closed) w, h, c = moil.getWidthHeightChannels(pred) try: M = cv2.moments(contour) cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) except Exception as e: print("No contour detected! Guessing for center...") cx = int(w / 2) cy = int(h / 2) w_scale = widthRef / w h_scale = heightRef / h cx = cx * w_scale cy = cy * h_scale return cx, cy
def OpticDiscPrediction(self): img = self.Mod.predict(self.currentImg) # img = moil.stackImageChannels(img) # resizing prediction w, h, c = moil.getWidthHeightChannels(self.currentImg) img = cv2.resize(img, (w, h)) # getting coords x, y = met.getCenter(img, w, h) x = int(x) y = int(y) return x, y, img
def check_performance(self, validate_generator, times=1, metrics=['distance', 'youden', 'jaccard', 'dice']): for i in range(times): pic = validate_generator.next() true = pic[1][0] pred = self.model.predict(pic[0][0].reshape( 1, self.rowDim, self.colDim, self.channels)) pred = moil.convertImageNetOutput(pred) true = moil.convertImageNetOutput(true) met.customMetric(pred, true, metrics=metrics) x = [] x.append(pic[0][0].reshape( (self.rowDim, self.colDim, self.channels))) x.append(true) x.append(pred) if self.show_function != None: self.show_function(x)
def __init__(self, repo_base, repo_name, new_name, size_level, scale=0.75, function=lambda x: x, onlyMasked=True, override=True): self.old_repo = repo_base + repo_name + '/' self.new_repo = repo_base + new_name + '/' self.target_size = moil.getColsRows(size_level, scale) self.onlyMasked = onlyMasked self.override = override self.function = function
def createImagesInRepoAfterFunctionOnPath(self, path, new_repo_path, function, target_size, override=False, extension='.jpg', onlyMasked=False): success = 0 fail = 0 repo_path, image_path = morn.getRepoPathAndImagePath(path) base2, name2 = BuildRepo.getBaseRepoPathAndRepoName(new_repo_path) BuildRepo.createImagesRepo(base2 + '/', name2) new_path = new_repo_path + image_path maskList = None if onlyMasked: maskList = mocl.getCsvList(repo_path, False) for a in os.listdir(path): if not os.path.isfile(os.path.join(path, a)): continue patient, date, eye = morn.getPatientDateEye(image_path) if onlyMasked and not os.path.isfile( os.path.join(path + 'mask/', a) ) and not mocl.checkIfExistsInCSV( [patient, date, eye, a], list=maskList, image=False): continue name = a.split(".")[0] base_image = moil.read_and_size(name, path=path, target_size=target_size) image = function(base_image) if morn.createImageInPath(new_path, name + extension, image, override): mocl.registerImageCsv(new_repo_path, image_path, name + extension, image, function) success += 1 else: fail += 1 return success, fail
def square_circle_on_1_2_in_path(path): for i in range(2): im, im_cp = moil.read_and_size_with_copy(str(i), scale=0.15) im = cf.equalize_border_with_mean_or_val(im) img_sqd = cf.square_circle_minus_filter_2d(im) img_sqd = cv2.equalizeHist(img_sqd) ret, imt = cv2.threshold(img_sqd, 254, 255, cv2.THRESH_BINARY) imt2, cnt, hier = cv2.findContours(imt, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) h, w = np.shape(im) r = (int)(h / 10) for j in range(len(cnt)): temp = cnt[j] M = cv2.moments(temp) cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) cv2.circle(im_cp, (cx, cy), r)
def callback(self): filename = filedialog.askopenfilename(title="Select file", filetypes=(("all files", "*.*"), ("jpeg files", "*.jpg"))) # filename = easygui.fileopenbox() self.root.update() if filename == '': return img = moil.read_and_size(name='', path=filename, extension='') self.currentImg = img self.x = -1 self.y = -1 self.atrophyRate = -1 self.distance = -1 self.xOut = -1 self.yOut = -1 self.predicted = False self.path = filename self.label.configure( text="Stopień zaniku (tylko faza tętniczo-żylna): ") self.updateGuiImage(img)
def centerDiff(pred, true=None, x=None, y=None, width=None, height=None, r=None, morph_iter=0, threshold=127, toDraw=None, retDist=False): assert true is not None or ( x is not None and y is not None and width is not None and height is not None and r is not None) thresh = moil.getBinaryThreshold(pred, threshold) closed = moil.morphMultiClosing(thresh, morph_iter) contour = moil.selectBiggerCircularContour(closed) if toDraw is not None and contour is not None: cv2.drawContours(toDraw, [contour], -1, (255, 255, 255), 1) w, h, c = moil.getWidthHeightChannels(pred) try: M = cv2.moments(contour) cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) except Exception as e: print("No contour detected! Guessing for center...") cx = int(w / 2) cy = int(h / 2) if (x is None or y is None or width is None or height is None or r is None): width, height, chan = moil.getWidthHeightChannels(true) r = width / 10 thresh = moil.getBinaryThreshold(true, threshold) im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) try: M = cv2.moments(contours[0]) x = int(M['m10'] / M['m00']) y = int(M['m01'] / M['m00']) except: print("Bad Ground-truth! Mask in center...") x = int(w / 2) y = int(h / 2) w_scale = width / w h_scale = height / h cx = cx * w_scale cy = cy * h_scale dist = np.linalg.norm(np.asarray([cx, cy]) - np.asarray([x, y])) if retDist: return dist maxDist = np.linalg.norm(np.asarray([w / 2, h / 2]) - np.asarray([x, y])) DistanceMetric = 1 - dist / maxDist CrossLength = math.sqrt(width ** 2 + height ** 2) DistanceToCross = dist / CrossLength print("Distance Metric: " + str(DistanceMetric) + ", Relative Distance: " + str( DistanceToCross) + ", Distance: " + str(dist)) return DistanceMetric
def LbpOnPath(self, path): for i in range(len(os.listdir(path)) - 1): img = moil.read_and_size(str(i), path=path, scale=self.scale) lbp = self.describe(img) moil.show(lbp, other_im=[img])
def circle_mask_on_random_image_in_path(self, path, target_size=None, r=None, extension=".jpg", check_csv=True, list=None): numb = len([ i for i in os.listdir(path) if os.path.isfile(os.path.join(path, i)) ]) temp = ([ a for a in os.listdir(path) if os.path.isfile(os.path.join(path, a)) ]) try: j = np.random.randint(numb) except: print(path + ", numb: " + str(numb)) return ImName = random.choice(temp) if not os.path.exists(path + '/mask'): os.makedirs(path + '/mask') tempName = path + '/mask/' + ImName if os.path.exists(tempName): print("Path exists (" + tempName + ")") return if check_csv: paths = morn.getRepoPathAndImagePath(path) row = paths[1].split("/")[:-1] row.append(ImName) if mocl.checkIfExistsInCSV(row, paths[0], list, False): print("In CSV exists (" + tempName + ")") return if r is None and target_size is not None: self.rr = int(target_size[0] / 10) else: self.rr = r img = moil.read_and_size(ImName, path=path, target_size=target_size, extension='') w, h, c = moil.getWidthHeightChannels(img) if r is None and target_size is None: self.rr = int(w / 10) target_size = (w, h) moil.show(img) accepted = False while not accepted: accepted = True im2, contours, hierarchy = cv2.findContours( self.mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) im2 = copy.deepcopy(img) cv2.drawContours(im2, contours, 0, (0, 255, 255), 2) moil.show(im2) split_path = path.split("/")[:-1] repo_path = reduce((lambda x, y: x + '/' + y), split_path[:len(split_path) - 3]) if not os.path.isfile(repo_path + "/maskData.csv"): csvFile = open(repo_path + '/maskData.csv', 'w', newline="") writer = csv.writer(csvFile) writer.writerow([ 'patient', 'date', 'eye', 'name', 'width', 'height', 'x', 'y', 'r' ]) csvFile.close() csvFile = open(repo_path + '/maskData.csv', 'a', newline="") writer = csv.writer(csvFile) ls = split_path[-3:] ls.extend([ ImName, target_size[0], target_size[1], self.xx, self.yy, self.rr ]) writer.writerow(ls) csvFile.close() cv2.imwrite(path + '/mask/' + ImName, self.mask) self.masks_done += 1 print("masks: " + str(self.masks_done)) cv2.destroyWindow('mask')
def validate(self, pathForce=None, validateMode=0, preprocessFunc=lambda x: x, draw=True, onlyWithMetric=False, onlyWithoutMetric=False, sumTimes=None, metrics=['distance', 'youden', 'jaccard', 'dice'], validTimes=1, weightsTimesValids=None, validName=''): avgs, globals = (0, 0) for i in range(validTimes): if weightsTimesValids is not None: self.constantVar = i * weightsTimesValids self.load_weights() sum = [0] * len(metrics) confusion_matrix = [0] * 4 globalCount = False for metr in metrics: if 'global' in metr: globalCount = True times = 0 visited_path = {} while True: if pathForce is None: path = self.validate_path_provider_func( self.validate_start_path, visited_path) visited_path[path] = times else: path = pathForce if path is None: break if not os.path.exists(path): continue images = os.listdir(path) for imp in images: # len(os.listdir(path)) - 2): true_path = path + 'mask/' if not os.path.exists(os.path.join(path, imp)): continue if onlyWithMetric and not os.path.exists( os.path.join(true_path, imp)): continue else: if onlyWithoutMetric and os.path.exists( os.path.join(true_path, imp)): continue im = self.read_func(name=imp, extension='', path=path, target_size=(self.colDim, self.rowDim), mode=0) imgX, img = self.prepareImage(im, retboth=True) pred = self.model.predict(imgX) pred = moil.convertImageNetOutput(pred) toDraw = im if draw else None x = [im, pred, img] if os.path.exists(os.path.join(true_path, imp)): true = self.read_func(name=imp, extension='', path=true_path, target_size=(self.colDim, self.rowDim)) true = true.reshape( (self.rowDim, self.colDim, self.out_channels)) x.append(true) results = met.customMetric(pred, true, toDraw=toDraw, metrics=metrics, globalCount=globalCount) sum = list(map(add, sum, results[0])) confusion_matrix = list( map(add, confusion_matrix, results[1])) times += 1 if sumTimes is not None and times >= sumTimes: break else: met.draw(pred, toDraw) if sumTimes is None: self.show_function(x) avgs = [x / times for x in sum] strgSum = '' strgAvgs = '' for val in sum: strgSum += str(val) + ', ' for val in avgs: strgAvgs += str(val) + ', ' globals = [] if globalCount: globals = met.globals(confusion_matrix) print("Global Jaccard: " + str(globals[0]) + ", Global Dice: " + str(globals[1])) print("Times: " + str(times) + ", sums: " + strgSum + "Average metrics: " + strgAvgs) self.validate_to_csv(metrics, avgs + globals, validName) return avgs + globals
def make_prediction(self): x, y, pred = self.OpticDiscPrediction() self.x = x self.y = y copy = self.currentImg.copy() drawCopy = self.currentImg.copy() drawCopy = moil.stackImageChannels(drawCopy) w, h, c = moil.getWidthHeightChannels(copy) xShift = int(80 * w / 600) yShift = int(80 * (w * 0.75) / 450) xExitShift = int(40 * w / 600) yExitShift = int(40 * (w * 0.75) / 450) roi = moil.getRegionOfInterest(copy, x, y, xShift, yShift) roiExit = moil.getRegionOfInterest(copy, x, y, xExitShift, yExitShift) atrophyRate, atrophyMap = self.AtrophyPrediction(roi) self.atrophyRate = atrophyRate self.label.configure( text="Stopień zaniku (tylko faza tętniczo-żylna): " + str(atrophyRate)) xExit, yExit = self.ExitPrediction(roiExit, xExitShift, yExitShift, x, y) self.xOut = xExit self.yOut = yExit dist = np.linalg.norm( np.asarray([xExit / w * 600, yExit / (w * 0.75) * 450]) - np.asarray([x / w * 600, y / (w * 0.75) * 450])) if dist > 16: self.labelExit.configure( text='Przesunięcie naczyń (faza tętniczo-żylna lub późna) : ' + str(dist) + ', ZNACZNE!') else: self.labelExit.configure( text='Przesunięcie naczyń (faza tętniczo-żylna lub późna) : ' + str(dist)) wA, hA, cA = moil.getWidthHeightChannels(atrophyMap) mask = np.zeros((h, w), drawCopy.dtype) mask = moil.addToRegionOfInterest(mask, x, y, round(wA / 2 + 0.00001), round(hA / 2 + 0.00001), atrophyMap) # mask[y-round(hA/2+0.00001):y+round(hA/2+0.00001), x-round(wA/2+0.00001):x+round(wA/2+0.00001)] = atrophyMap redImg = np.zeros(drawCopy.shape, drawCopy.dtype) redImg[:, :] = (255, 0, 0) redMask = cv2.bitwise_and(redImg, redImg, mask=mask) drawCopy = cv2.addWeighted(redMask, 1, drawCopy, 1, 0) # moil.show(atrophyMap) # drawCopy[mask] = (255, 0, 0) cv2.rectangle(drawCopy, (x - xShift, y - yShift), (x + xShift, y + yShift), (127, 0, 127), int(5 / 1387 * w)) cv2.circle(drawCopy, (x, y), int(12 / 1387 * w), (127, 0, 127), thickness=int(5 / 1387 * w)) met.draw(pred, drawCopy, thickness=int(4 / 1387 * w)) cv2.circle(drawCopy, (xExit, yExit), int(12 / 1387 * w), (0, 127, 0), thickness=int(5 / 1387 * w)) self.updateGuiImage(drawCopy) self.predicted = True
def model_show_function(x): y = [] for i in range(len(x) - 1): y.append(x[i + 1]) moil.show(x[0], other_im=y)
def MergeOnPath(self, path): for i in range(len(os.listdir(path)) - 1): img = moil.read_and_size(str(i), path=path, scale=0.3) merged = self.Merge(img) moil.show(merged, other_im=[img])
import cv2 import Code.Libraries.MyOculusImageLib as moil import Code.Libraries.MyOculusRepoNav as morn import os path = '../../../Images/ZanikGray50/' dict = {} while True: im_path = morn.next_path(path, dict) dict[im_path] = True if not os.path.exists(im_path): continue ims = os.listdir(im_path) for im in ims: if not os.path.isfile(im_path + im): continue img = moil.read_and_size(name=im, path=im_path, scale=1, extension='') img2 = cv2.equalizeHist(img) moil.show(img, other_im=[img2])
def trackback_callback(x): global track_val track_val = x def track(name, max, start=0, win='win'): cv2.createTrackbar(name, win, start, max, trackback_callback) def get_track(name, win='win'): return cv2.getTrackbarPos(name, win) for i in range(get_number_of_images_in_path(path)): im, im_cp = moil.read_and_size_with_copy(str(i), scale=0.15) cf.equalize_border_with_mean_or_val(im) negative = False if i >= 2 and i <= 5: negative = True track('thresh', 255) track('r', 100) while (cv2.waitKey(30) != ord('q')): img = cf.circle_filter_2d(im, get_track('r') + 1) img_sqd = cf.square_circle_minus_filter_2d(im, get_track('r') + 1, negative)
base_path = '../' image_size_level = 20 base_scale = 0.75 withMetricOrNo = 1 onlyWithMetric = False onlyWithoutMetric = False if withMetricOrNo == 1: onlyWithMetric = True if withMetricOrNo == 2: onlyWithoutMetric = True batch_size = 32 total_ep = 1 ep = 500 steps = 10 cols, rows = moil.getColsRows(level=image_size_level, base_scale=base_scale) gray = True if (gray): mode = 0 channels_in = 1 color_mode = 'grayscale' else: mode = 1 channels_in = 3 color_mode = 'rgb' # data augmentation aug = dac.getAugmentationParams() FeatureName = "Tarcza"
def GradientSumOnPath(self, path): for i in range(len(os.listdir(path)) - 1): img = moil.read_and_size(str(i), path=path, scale= self.scale) grad = self.getGradientSum(img) moil.show(grad, other_im=[img])