def getModelPointsAutoWhole(personId): image = rg.readRadioGraph(personId) sumScrs = 0 avgTeeth = np.zeros((main.nbLandmarks, main.toothIds.shape[0], 2)) corrLM = np.zeros((main.nbLandmarks, main.toothIds.shape[0], 2)) for templId in range(14): # get the template templImg, templLM = mt.getTemplate(templId, main.toothIds) # match the template (x,y), scale, scr = mt.matchTemplate(image, templImg) # translate the template landmarks for i in range(main.toothIds.shape[0]): corrLM[:,i,:] = procru.scaleMatrixForPerson(templLM[:,i,:], scale) corrLM[:,i,:] = procru.translateMatrixForPerson(corrLM[:,i,:], np.array([[x],[y]])) # add the translated landmarks to the average tooth with weight = scr avgTeeth = avgTeeth + scr**main.templ_scr_loyalty*corrLM # update the sum of all scores sumScrs = sumScrs + scr**main.templ_scr_loyalty avgTeeth = avgTeeth/sumScrs #for i in range(8): # cv2.polylines(image, np.int32([avgTeeth[:,i,:]]), True, 255) #main.showScaled(image, 0.6, 'automatic initialisation', True) return avgTeeth
def testMatchTemplate(): for personId in range(14, 30): image = rg.readRadioGraph(personId) chosenScr = 0 for templId in range(14): template = getTemplate(templId, np.array(range(8))) (x, y), scale, scr = matchTemplate(image, template[0]) if scr > chosenScr: chosenScr = scr chosenX = x chosenY = y chosenTemplate = template chosenTemplId = templId print(personId, chosenTemplId) main.showScaled(template[0], 0.66, 'template', True) main.showScaled(templFilter(image), 0.66, 'image', True) combined = image.copy() #combined[x:x+template[0].shape[0], y:y+template[0].shape[1]] = template[0] cv2.circle(combined, (y, x), 3, 128, thickness=-1) #main.showScaled(combined, 0.66, 'combined', False) init_image = image.copy() for toothId in range(8): init_points = procru.translateMatrixForPerson( chosenTemplate[1][:, toothId, :], np.array([[chosenX], [chosenY]])) cv2.polylines(init_image, np.int32([init_points]), True, 255) cv2.imshow('init_image', init_image) main.showScaled(init_image, 0.66, 'init_image', True)
def getTemplate(personId, toothIds, Delta=15): # read landmarks and image landmarks = lm.readLandmarksOfPersonAndTeeth(personId, toothIds) image = rg.readRadioGraph(personId) # crop image to box around landmarks minX = np.min(landmarks[:, :, 0]) - Delta maxX = np.max(landmarks[:, :, 0]) + Delta minY = np.min(landmarks[:, :, 1]) - Delta maxY = np.max(landmarks[:, :, 1]) + Delta image = image[minY:maxY, minX:maxX] # translate landmarks to the coordinate system of the cropped image for i in range(toothIds.shape[0]): landmarks[:, i, :] = procru.translateMatrixForPerson( landmarks[:, i, :], np.array([[-minX], [-minY]])) return image, landmarks
def getModelPointsManually(personId, toothId): image = rg.readRadioGraph(personId) image = cv2.resize(image, (0,0), fx=main.windowscale, fy=main.windowscale) cv2.namedWindow('points') cv2.cv.SetMouseCallback('points', mouseCallback, image) cv2.imshow('points', image) print 'Click initial points for tooth #' + str(toothId) cv2.waitKey(0) pointsLength = len(xPoints) points = np.zeros((pointsLength, 2)) for i in range(pointsLength): points[i,0] = xPoints[i]/main.windowscale points[i,1] = yPoints[i]/main.windowscale print points return points
def getModelPointsAutoParts(personId): debugMBB = True image = rg.readRadioGraph(personId) # Choice of search area around the upper resp. lower inscisors within (preprocessed) image, for finding parts (upper and lower part) in an image ## these coordinates are in the not-preprocessed images, format Part x {UpperLeft, LowerRight} x Dim partSearchAreas = np.array([[[1190,550], [1830,1120]], [[1210,880], [1810,1400]]]) ## correct for preprocessing of images partSearchAreas[:,:,0] = partSearchAreas[:,:,0] - np.ones_like(partSearchAreas[:,:,0])*rg.cropX[0] partSearchAreas[:,:,1] = partSearchAreas[:,:,1] - np.ones_like(partSearchAreas[:,:,1])*rg.cropY[0] if debugMBB: debugImage = image.copy() cv2.rectangle(debugImage, (partSearchAreas[0,0,0], partSearchAreas[0,0,1]), (partSearchAreas[0,1,0], partSearchAreas[0,1,1]), 255) cv2.rectangle(debugImage, (partSearchAreas[1,0,0], partSearchAreas[1,0,1]), (partSearchAreas[1,1,0], partSearchAreas[1,1,1]), 255) #main.showScaled(debugImage, 0.6, 'debugImage', True) ## get search images (image cropped to resp. search area) upperImage = image.copy()[partSearchAreas[0,0,1]:partSearchAreas[0,1,1], partSearchAreas[0,0,0]:partSearchAreas[0,1,0]] lowerImage = image.copy()[partSearchAreas[1,0,1]:partSearchAreas[1,1,1], partSearchAreas[1,0,0]:partSearchAreas[1,1,0]] sumUpScrs = 0 sumLowScrs = 0 avgUpTeeth = np.zeros((main.nbLandmarks, 4, 2)) avgLowTeeth = np.zeros((main.nbLandmarks, 4, 2)) upLMs = np.zeros((main.nbLandmarks, 4, 2)) lowLMs = np.zeros((main.nbLandmarks, 4, 2)) for templId in range(14): ## get templates for these parts upTemplImg, upTemplLMs = mt.getTemplate(templId, np.array(range(4)), Delta=0) lowTemplImg, lowTemplLMs = mt.getTemplate(templId, np.array(range(4,8)), Delta=0) ## match templates (upX,upY), upScale, upScore = mt.matchTemplate(upperImage, upTemplImg) (lowX,lowY), lowScale, lowScore = mt.matchTemplate(lowerImage, lowTemplImg) ## avoid deviding by zero when loyalty to best fit is high if upScore == 0 : upScore = 1 if lowScore == 0 : lowScore = 1 # translate and scale the found landmarks for toothIdy in range(4): upLMs[:,toothIdy,:] = procru.scaleMatrixForPerson(upTemplLMs[:,toothIdy,:], upScale) upLMs[:,toothIdy,:] = procru.translateMatrixForPerson(upLMs[:,toothIdy,:], np.array([[upX + partSearchAreas[0,0,0]], [upY + partSearchAreas[0,0,1]]])) lowLMs[:,toothIdy,:] = procru.scaleMatrixForPerson(lowTemplLMs[:,toothIdy,:], lowScale) lowLMs[:,toothIdy,:] = procru.translateMatrixForPerson(lowLMs[:,toothIdy,:], np.array([[lowX + partSearchAreas[1,0,0]], [lowY + partSearchAreas[1,0,1]]])) # updat the average teeth avgUpTeeth = avgUpTeeth + upScore**main.templ_scr_loyalty*upLMs avgLowTeeth = avgLowTeeth + lowScore**main.templ_scr_loyalty*lowLMs # update the sum of all scores sumUpScrs = sumUpScrs + upScore**main.templ_scr_loyalty sumLowScrs = sumLowScrs + lowScore**main.templ_scr_loyalty # merge parts into one matrix avgTeeth = np.zeros((main.nbLandmarks, 8, 2)) avgTeeth[:,0:4,:] = avgUpTeeth/sumUpScrs avgTeeth[:,4:8,:] = avgLowTeeth/sumLowScrs return avgTeeth
def getModelPointsAutoTeeth(personId): debugMBB = True image = rg.readRadioGraph(personId) # Choice of search area around the upper resp. lower inscisors within (preprocessed) image, for finding parts (upper and lower part) in an image ## these coordinates are in the not-preprocessed images, format Part x {UpperLeft, LowerRight} x Dim partSearchAreas = np.array([[[1190,550], [1830,1120]], [[1210,880], [1810,1400]]]) ## correct for preprocessing of images partSearchAreas[:,:,0] = partSearchAreas[:,:,0] - np.ones_like(partSearchAreas[:,:,0])*rg.cropX[0] partSearchAreas[:,:,1] = partSearchAreas[:,:,1] - np.ones_like(partSearchAreas[:,:,1])*rg.cropY[0] if debugMBB: debugImage = image.copy() cv2.rectangle(debugImage, (partSearchAreas[0,0,0], partSearchAreas[0,0,1]), (partSearchAreas[0,1,0], partSearchAreas[0,1,1]), 255) cv2.rectangle(debugImage, (partSearchAreas[1,0,0], partSearchAreas[1,0,1]), (partSearchAreas[1,1,0], partSearchAreas[1,1,1]), 255) #main.showScaled(debugImage, 0.6, 'debugImage', True) # 1 FIND BOUNDING BOXES OF PARTS IN SEARCH AREA if debugMBB: ''' avgUpTeeth = np.zeros((main.nbLandmarks, 4, 2)) avgLowTeeth = np.zeros((main.nbLandmarks, 4, 2)) ''' ## get search images (image cropped to resp. search area) upperImage = image.copy()[partSearchAreas[0,0,1]:partSearchAreas[0,1,1], partSearchAreas[0,0,0]:partSearchAreas[0,1,0]] lowerImage = image.copy()[partSearchAreas[1,0,1]:partSearchAreas[1,1,1], partSearchAreas[1,0,0]:partSearchAreas[1,1,0]] upMBBUL = np.zeros((2,)) upMBBLR = np.zeros((2,)) lowMBBUL = np.zeros((2,)) lowMBBLR = np.zeros((2,)) sumUpScrs = 0 sumLowScrs = 0 for templId in range(14): ## get templates for these parts upTemplImg, upTemplLMs = mt.getTemplate(templId, np.array(range(4)), Delta=0) lowTemplImg, lowTemplLMs = mt.getTemplate(templId, np.array(range(4,8)), Delta=0) ## match templates (upX,upY), upScale, upScore = mt.matchTemplate(upperImage, upTemplImg) (lowX,lowY), lowScale, lowScore = mt.matchTemplate(lowerImage, lowTemplImg) ## avoid deviding by zero if upScore == 0 : upScore = 1 if lowScore == 0 : lowScore = 1 ## calculate matched bounding box (MBB) corners, relative to the preprocessed image (image) upMBBUL = upMBBUL + (upScore**main.templ_scr_loyalty)*( np.array([upX,upY]) + partSearchAreas[0,0,:] ) upMBBLR = upMBBLR + (upScore**main.templ_scr_loyalty)*( np.array([upX,upY]) + partSearchAreas[0,0,:] + np.array([upTemplImg.shape[1]*upScale, upTemplImg.shape[0]*upScale]) ) lowMBBUL = lowMBBUL + (lowScore**main.templ_scr_loyalty)*( np.array([lowX,lowY]) + partSearchAreas[1,0,:] ) lowMBBLR = lowMBBLR + (lowScore**main.templ_scr_loyalty)*( np.array([lowX,lowY]) + partSearchAreas[1,0,:] + np.array([lowTemplImg.shape[1]*lowScale, lowTemplImg.shape[0]*lowScale]) ) # update the sum of all scores sumUpScrs = sumUpScrs + upScore**main.templ_scr_loyalty sumLowScrs = sumLowScrs + lowScore**main.templ_scr_loyalty ## calculate average MBB and correct for search area upMBBUL = np.int32(upMBBUL/sumUpScrs) upMBBLR = np.int32(upMBBLR/sumUpScrs) lowMBBUL = np.int32(lowMBBUL/sumLowScrs) lowMBBLR = np.int32(lowMBBLR/sumLowScrs) #if debugMBB: #cv2.rectangle(debugImage, (upMBBUL[0], upMBBUL[1] ), (upMBBLR[0], upMBBLR[1] ), 255) #cv2.rectangle(debugImage, (lowMBBUL[0],lowMBBUL[1]), (lowMBBLR[0],lowMBBLR[1]), 255) #2 FIND LOCATION OF TEETH IN FOUND BOUNDING BOXES # Choise of search space for each inscisor ## the numbers in this table are the relative, horizontal borders of ## the search area within the matched bounding box of the resp. part, format Tooth x {LeftBorder, RightBorder} searchBoxBorders = np.array([[0.0,0.3], [0.2,0.6], [0.4,0.8], [0.7,1.0], [0.0,0.3], [0.2,0.6], [0.4,0.8], [0.7,1.0]]) ''' searchBoxBorders = np.array([[0.0,0.25], [0.25,0.5], [0.5,0.75], [0.75,1.0], [0.0,0.25], [0.25,0.5], [0.5,0.75], [0.75,1.0]]) ''' ## widths of the parts upDeltaX = upMBBLR[0]-upMBBUL[0] lowDeltaX = lowMBBLR[0]-lowMBBUL[0] ## Choice of extra space to add around the searchboxes extraSearchSpace = 30 searchBoxes = np.zeros((8,2,2)) # Tooth x {UpperLeft, LowerRight} x Dim ## calculate search boxes for teeth for toothIdx in range(4): searchBoxes[toothIdx,0,0] = upMBBUL[0] + upDeltaX*searchBoxBorders[toothIdx,0] - extraSearchSpace # upper part, upper left x searchBoxes[toothIdx,0,1] = upMBBUL[1] - extraSearchSpace # upper part, upper left y searchBoxes[toothIdx,1,0] = upMBBUL[0] + upDeltaX*searchBoxBorders[toothIdx,1] + extraSearchSpace # upper part, lower right x searchBoxes[toothIdx,1,1] = upMBBLR[1] + extraSearchSpace # upper part, lower right y if debugMBB : cv2.rectangle(debugImage, (np.int(searchBoxes[toothIdx,0,0]), np.int(searchBoxes[toothIdx,0,1])), (np.int(searchBoxes[toothIdx,1,0]), np.int(searchBoxes[toothIdx,1,1])), 255) for toothIdx in range(4,8): searchBoxes[toothIdx,0,0] = lowMBBUL[0] + lowDeltaX*searchBoxBorders[toothIdx,0] - extraSearchSpace # lower part, upper left x searchBoxes[toothIdx,0,1] = lowMBBUL[1] - extraSearchSpace # lower part, upper left y searchBoxes[toothIdx,1,0] = lowMBBUL[0] + lowDeltaX*searchBoxBorders[toothIdx,1] + extraSearchSpace # lower part, lower right x searchBoxes[toothIdx,1,1] = lowMBBLR[1] + extraSearchSpace # lower part, lower right y if debugMBB : cv2.rectangle(debugImage, (np.int(searchBoxes[toothIdx,0,0]), np.int(searchBoxes[toothIdx,0,1])), (np.int(searchBoxes[toothIdx,1,0]), np.int(searchBoxes[toothIdx,1,1])), 255) avgTeeth = np.zeros((main.nbLandmarks, 8, 2)) for toothId in range(8): searchImage = image.copy()[searchBoxes[toothId,0,1]:searchBoxes[toothId,1,1],searchBoxes[toothId,0,0]:searchBoxes[toothId,1,0]] sumScrs = 0 corrLM = np.zeros((main.nbLandmarks, 2)) #main.showScaled(searchImage, 1.5, 'searchImage', True) for templId in range(14): templImg, templLMs = mt.getTemplate(templId, np.array([toothId]), Delta = 0) #main.showScaled(templImg, 1.5, 'template', True) (x,y), scale, scr = mt.matchTemplate(searchImage, templImg) # translate the template landmarks corrLM = procru.scaleMatrixForPerson(templLMs[:,0,:], scale) corrLM = procru.translateMatrixForPerson(corrLM, np.array([[searchBoxes[toothId,0,0]],[searchBoxes[toothId,0,1]]])) corrLM = procru.translateMatrixForPerson(corrLM, np.array([[x],[y]])) # add the translated landmarks to the average tooth with weight = scr avgTeeth[:,toothId,:] = avgTeeth[:,toothId,:] + scr**main.templ_scr_loyalty*corrLM # update the sum of all scores sumScrs = sumScrs + scr**main.templ_scr_loyalty avgTeeth[:,toothId,:] = avgTeeth[:,toothId,:]/sumScrs if debugMBB : cv2.polylines(debugImage, np.int32([avgTeeth[:,toothId,:]]), True, 255) #if debugMBB : main.showScaled(debugImage, 0.6, 'hierarchical initialisation', True) return avgTeeth
''' def getVerticalMiddleOfTeeth(image): y_min = np.argmin(np.average(image, 1)) line = np.int32([np.array([[0,y_min],[image.shape[1]-1, y_min]])]) cv2.polylines(image, line, False, 255) cv2.imshow('result', image) cv2.waitKey(0) ''' MAIN PROGRAM ''' if __name__ == '__main__': for personId in range(14,30): imageWhole = rg.readRadioGraph(personId) imageParts = imageWhole.copy() imageTeeth = imageWhole.copy() resultWhole = getModelPointsAutoWhole(personId) resultParts = getModelPointsAutoParts(personId) resultTeeth = getModelPointsAutoTeeth(personId) for toothId in range(8): cv2.polylines(imageWhole, np.int32([resultWhole[:,toothId,:]]), True, 255) cv2.polylines(imageParts, np.int32([resultParts[:,toothId,:]]), True, 255) cv2.polylines(imageTeeth, np.int32([resultTeeth[:,toothId,:]]), True, 255) ''' main.showScaled(imageWhole, 0.6, 'whole', False) main.showScaled(imageParts, 0.6, 'parts', False) main.showScaled(imageTeeth, 0.6, 'teeth', True)
def findSegments(): # load training radiographs images = rg.readRadiographs(trainingPersonIds) if debugFB: print 'DB: Training radiographs loaded' for personToFitId in personToFitIds: # load radiograph to determine segments for imageToFit = rg.readRadioGraph(personToFitId) if debugFB: print 'DB: Radiograph to fit (#' + str(personToFitId + 1) + ') loaded' contourImage = imageToFit.copy() segmentsImage = np.zeros_like(np.array(imageToFit)) if autoInitPoints: init_points = ip.getModelPointsAutoWhole(personToFitId) for i in range(toothIds.shape[0]): toothId = toothIds[i] # Read data (images and landmarks) landmarks = lm.readLandmarksOfTooth(toothId, trainingPersonIds) if debugFB: print ' DB: Landmarks loaded for tooth #' + str(toothId + 1) # Initialization of mean vector (xStriped), covariance matrix, x-vector, x-striped-vector (mean), eigenvectors (P) and eigenvalues. processedLandmarks = procrustes.procrustesMatrix(landmarks, 100) if debugFB: print ' DB: Procrustes ready for tooth #' + str(toothId + 1) pcMean, pcEigv = cv2.PCACompute( np.transpose(stackPoints(processedLandmarks))) if debugFB: print ' DB: PCA ready for tooth #' + str(toothId + 1) xStacked = xStriped = np.transpose(pcMean) covar, _ = cv2.calcCovarMatrix( stackPoints(processedLandmarks), cv2.cv.CV_COVAR_SCRAMBLED | cv2.cv.CV_COVAR_SCALE | cv2.cv.CV_COVAR_COLS) eigval = np.sort(np.linalg.eigvals(covar), kind='mergesort')[::-1] # Number of modes coverage = 0 nbModes = 0 eigval_total = np.sum(eigval) for value in eigval: coverage += value / eigval_total nbModes += 1 if coverage >= 0.99: break P = np.transpose(pcEigv[:nbModes]) # normalized eigval = eigval[:nbModes] # Initialization of the initial points if autoInitPoints: X = init_points[:, toothId, :] else: X = ip.getModelPointsManually(personToFitId, toothId) # Draw the initial points initialImage = imageToFit.copy() cv2.polylines(initialImage, np.int32([X]), True, 255, thickness=2) #showScaled(initialImage, windowscale, 'initial', False) # Initialize the model directions = profile.getDirections(landmarks) model = profile.getModel(images, landmarks, directions, nModel) ## Protocol 1: step 1 (initialize shape parameters) b = np.zeros((nbModes, 1)) prev_b = b stop = False it = 1 while (not stop): # Protocol 2: step 1 (examine region around each point to find best nearby match) Y = profile.getNewModelPoints(imageToFit, X, model, nSample) # Protocol 2: step 3 = protocol 1 ## Protocol 1: step 2 (generate model point positions) xStacked = xStriped + np.dot(P, b) ## Protocol 1: step 3 & 4 (project Y into the model coordinate frame) y, translation = procrustes.procrustesTranslateMatrixForPerson( Y) scale, rotation = procrustes.alignShapes( unstackPointsForPerson(xStacked), y) translation = -translation y = procrustes.rotateMatrixForPerson(y, -rotation) y = procrustes.scaleMatrixForPerson(y, 1 / scale) ## Protocol 1: step 5 --> NOT NEEDED?? #yStacked = stackPointsForPerson(y) #yStacked = yStacked/np.dot(np.transpose(yStacked), xStriped) #y = unstackPointsForPerson(yStacked) ## Protocol 1: step 6 (update model parameters) b = np.dot(np.transpose(P), (stackPointsForPerson(y) - xStriped)) # Protocol 2: step 3 (apply constraints to b) #mahalonobis = np.sqrt(np.sum(b**2)/np.sum(eigval)) #if mahalonobis > 3.0: # b = b*(3.0/mahalonobis) for i in range(b.shape[0]): if np.abs(b[i, 0]) > 3 * np.sqrt(eigval[i]): b[i, 0] = np.sign(b[i, 0]) * 3 * np.sqrt(eigval[i]) # Calculate difference with previous result # and stop iterating after a certain threshold differences = prev_b - b prev_b = b stop = True for diff in differences: if np.abs(diff) > 0.01: stop = False it += 1 if debugFB: print ' DB: Tooth #' + str( toothId + 1) + ' finished in ' + str(it) + ' iterations.' # Draw the model on the radiograph x = unstackPointsForPerson(xStriped + np.dot(P, b)) X = procrustes.rotateMatrixForPerson(x, rotation) X = procrustes.scaleMatrixForPerson(X, scale) X = procrustes.translateMatrixForPerson(X, translation) cv2.polylines(contourImage, np.int32([X]), True, 255, thickness=2) #showScaled(contourImage, windowscale, 'contours', True) cv2.fillPoly(segmentsImage, np.int32([[X]]), 128) #showScaled(segmentsImage, windowscale, 'segments', True) #cv2.imwrite('C:/Users/samue_000/Desktop/' + str(personToFitId+1) + 'i.jpg', initialImage) #cv2.imwrite('C:/Users/samue_000/Desktop/' + str(personToFitId+1) + 'c.jpg', contourImage) #cv2.imwrite('C:/Users/samue_000/Desktop/' + str(personToFitId+1) + 's.jpg', segmentsImage) showScaled(contourImage, windowscale, 'contours', True) print 'DB: Radiograph #' + str(personToFitId + 1) + ' is segmented.'
def testMatchTemplateFilter(): for personId in range(14, 30): # WITHOUT FILTER image = rg.readRadioGraph(personId) sumScrs = 0 avgTeeth = np.zeros((main.nbLandmarks, main.toothIds.shape[0], 2)) corrLM = np.zeros((main.nbLandmarks, main.toothIds.shape[0], 2)) for templId in range(14): # get the template templImg, templLM = getTemplate(templId, np.array(range(8))) # match the template (x, y), scale, scr = matchTemplate(image, templImg) # translate the template landmarks for i in range(main.toothIds.shape[0]): toothIdx = main.toothIds[i] corrLM[:, toothIdx, :] = procru.scaleMatrixForPerson( templLM[:, toothIdx, :], scale) corrLM[:, toothIdx, :] = procru.translateMatrixForPerson( corrLM[:, toothIdx, :], np.array([[x], [y]])) # add the translated landmarks to the average tooth with weight = scr avgTeeth = avgTeeth + scr**main.templ_scr_loyalty * corrLM # update the sum of all scores sumScrs = sumScrs + scr**main.templ_scr_loyalty avgTeeth = avgTeeth / sumScrs init_image = image.copy() for toothId in range(8): cv2.polylines(init_image, np.int32([avgTeeth[:, toothId, :]]), True, 255) main.showScaled(init_image, 0.66, 'without filter', True) # WITH FILTER image = rg.readRadioGraph(personId) sumScrs = 0 avgTeeth = np.zeros((main.nbLandmarks, main.toothIds.shape[0], 2)) corrLM = np.zeros((main.nbLandmarks, main.toothIds.shape[0], 2)) for templId in range(14): # get the template templImg, templLM = getTemplate(templId, np.array(range(8))) # match the template (x, y), scale, scr = matchTemplate(templFilter(image), templFilter(templImg)) # translate the template landmarks for i in range(main.toothIds.shape[0]): toothIdx = main.toothIds[i] corrLM[:, toothIdx, :] = procru.scaleMatrixForPerson( templLM[:, toothIdx, :], scale) corrLM[:, toothIdx, :] = procru.translateMatrixForPerson( corrLM[:, toothIdx, :], np.array([[x], [y]])) # add the translated landmarks to the average tooth with weight = scr avgTeeth = avgTeeth + scr**main.templ_scr_loyalty * corrLM # update the sum of all scores sumScrs = sumScrs + scr**main.templ_scr_loyalty avgTeeth = avgTeeth / sumScrs init_image = image.copy() for toothId in range(8): cv2.polylines(init_image, np.int32([avgTeeth[:, toothId, :]]), True, 255) main.showScaled(init_image, 0.66, 'with filter', True)