def loadBalloonsFromSVG(filename, foldername, tagName, attributeClass, verbose): polygons = [] contours = [] #w, h = imgSize nbContour = 0 #nbMatch = 0 #nbSmooth = 0 #nbWavy = 0 #nbZigzag = 0 #nbNoTMatch = 0 sumMeanHeight = 0 #s = filepath.split(os.sep) #filepath = s[len(s) - 1] if verbose: img = cv2.imread('/media/Donnees/DATA/DATASET/eBDtheque_100/'+filename.split('.')[0]+'.jpg') if not filename.endswith('svg'): print 'ERROR in loadBalloonsFromSVG: not an SVG file (',filename,')' return w, h = toolbox_svg.getImageSizeFromSvg(foldername+filename) xmldoc = parse(foldername+filename) itemlist = xmldoc.getElementsByTagName(tagName) # find all polygon elements #contoursSVGImg = numpy.zeros([h, w], numpy.uint8) #defectsImg = numpy.zeros([h, w], numpy.uint8) itemListIterator = 0 for item in itemlist : # process only polygon that are in a svg tag with class=Balloon if item.parentNode.attributes['class'].value == attributeClass: points = item.attributes['points'].value coords = points.split(' ') balloonType = 'unknown' #if loadTypeFromText: # balloonType = getTypeFromTextFile(filepath.split('.')[0]+'.txt', itemListIterator) # itemListIterator += 1 #else: # for child in item.childNodes: # if child.nodeType == 1: # balloonType = child.attributes['shape'].value #if balloonType == 'unknown' or balloonType == '': # print 'WARNING: unknwon or empty balloon type in',filepath, #Convert point list into an array contour = toolbox_svg.svgList2NumpyArray(coords) #Barycenter M = cv2.moments(contour) try: c_x = int(M['m10']/M['m00']) c_y = int(M['m01']/M['m00']) except: print 'ERROR: division by zero in barycenter of contour',contour,'in file',filename,'(coords=',coords,')' c_x = 0 c_y = 0 #Spacial position of the balloon t, b, l, r = coord2box(coords, w, h)#xList, yList, w, h ) #coef = 100 / max((b-t),(r-l))# / 100.0 #contourDiv = rint(contour/coef).astype(int) #divide the contour by a scalar and keep the closest integer value. Then convert as integer #print 'coef=',coef,'contour=',contour,'contourDiv=',contourDiv #Draw contour to equalize the number of points newDrawing = numpy.zeros([h, w], numpy.uint8) cv2.drawContours(newDrawing,[contour],0,(100,50,255),0) #Normalize and detect again contour (spatial lost) newContours, hierachy = cv2.findContours(newDrawing.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) newContour = newContours[0] #Get tail direction and position fro metadata tag tailDirection = item.childNodes[1].attributes['tailDirection'].value tailTip = item.childNodes[1].attributes['tailTip'].value #if verbose: # cv2.circle(img,(c_x, c_y),1,[255,0,0],2) #plot barycenter for thumbnail # cv2.circle(img,tuple(newContour[0][0]),1,[0,255,0],2) #plot starting point for thumbnail if verbose: #Draw contour cv2.drawContours(img,[newContour],0,(255,0,0),1) #RGB #Draw position line if tailTip != '': x1, y1 = tailTip.split(',') cv2.circle(img, (int(x1), int(y1)), 5, (0,255,0), 2) thumbnail = img[t:b, l:r] else: thumbnail = None #New MyBalloon object myBalloon = class_balloon.MyBalloon(points, [c_x, c_y], newContour, balloonType, [t, b, l, r], thumbnail, [c_x, c_y], tailTip, tailDirection ) #Add new contour to the contour list contours.append(myBalloon) del contour #if verbose: #Draw contour for later use #cv2.drawContours(img,[newContour],0,(255,0,0),1) #RGB nbContour += 1 return contours
def evaluateTailExtraction(f, inputSVGGroundtruth, inputSVGDetection, outputFolderPNG, verbose): """ Evaluate the tail detection using recall and precision """ #Load balloons detections and ground truth balloonsFromExtractor = loadBalloonsFromSVG(f, inputSVGDetection, 'polygon', 'Balloon', verbose) balloonsFromGroundtruth = loadBalloonsFromSVG(f, inputSVGGroundtruth, 'polygon', 'Balloon', verbose) width, height = toolbox_svg.getImageSizeFromSvg(inputSVGGroundtruth+f) matchList = [] precision = 0 recall = 0 nbWrong = 0 found = 0 nb = 0 for balloonExt in balloonsFromExtractor: #Ckecking #assert balloonExt.tailDirection != '' , 'ERROR: tail direction is not set for balloon'+str(balloonExt.BdB)+' in file '+f if balloonExt.tailDirection != '': print '\nERROR: tail direction is not set for balloon'+str(balloonExt.BdB)+' in file '+f #Find corresponding balloon with the biggest sharing intersection balloonMatchGT = getMaxMatchV2(width, height, balloonExt, balloonsFromGroundtruth, outputFolderPNG, verbose) if balloonMatchGT == None: if verbose: print '\nERROR: balloon match not found (no evaluation then) for '+str(balloonExt.BdB)+' in '+f continue pointList = balloonMatchGT.getPoints() if pointList in matchList: if verbose: print 'ERROR duplicate point list (no evaluation then) in',inputSVGDetection+f,'(',pointList,')' continue matchList.append(pointList) #Position (recall) # try: if balloonMatchGT.tailCoordinates == balloonExt.tailCoordinates: recall += 1 #if both have the same value (none OR '' OR X,Y coordinates) elif balloonMatchGT.tailCoordinates == '' or balloonExt.tailCoordinates == '': recall += 0 #if only one is empty else: try: if (int(balloonMatchGT.tailCoordinates[0]) - 10 < int(balloonExt.tailCoordinates[0]) < int(balloonMatchGT.tailCoordinates[0]) + 10) and (int(balloonMatchGT.tailCoordinates[1]) - 10 < int(balloonExt.tailCoordinates[1]) < int(balloonMatchGT.tailCoordinates[1]) + 10): recall += 1 elif (int(balloonMatchGT.tailCoordinates[0]) - 20 < int(balloonExt.tailCoordinates[0]) < int(balloonMatchGT.tailCoordinates[0]) + 20) and (int(balloonMatchGT.tailCoordinates[1]) - 20 < int(balloonExt.tailCoordinates[1]) < int(balloonMatchGT.tailCoordinates[1]) + 20): recall += 0.5 except: recall += 0 print 'WARNING: set recall=0 for',balloonExt.tailCoordinates,'and',balloonMatchGT.tailCoordinates,'for balloon',balloonExt.BdB,'in',f #Direction (precision) if balloonExt.tailDirection == balloonMatchGT.tailDirection: precision += 1 found = 1 elif balloonExt.tailDirection == 'S' and (balloonMatchGT.tailDirection == 'SE' or balloonMatchGT.tailDirection == 'SW'): precision += 0.5 found = 0.5 elif balloonExt.tailDirection == 'SE' and (balloonMatchGT.tailDirection == 'S' or balloonMatchGT.tailDirection == 'E'): precision += 0.5 found = 0.5 elif balloonExt.tailDirection == 'E' and (balloonMatchGT.tailDirection == 'SE' or balloonMatchGT.tailDirection == 'NE'): precision += 0.5 found = 0.5 elif balloonExt.tailDirection == 'NE' and (balloonMatchGT.tailDirection == 'S' or balloonMatchGT.tailDirection == 'N'): precision += 0.5 found = 0.5 elif balloonExt.tailDirection == 'N' and (balloonMatchGT.tailDirection == 'NE' or balloonMatchGT.tailDirection == 'NW'): precision += 0.5 found = 0.5 elif balloonExt.tailDirection == 'NW' and (balloonMatchGT.tailDirection == 'N' or balloonMatchGT.tailDirection == 'W'): precision += 0.5 found = 0.5 elif balloonExt.tailDirection == 'W' and (balloonMatchGT.tailDirection == 'NW' or balloonMatchGT.tailDirection == 'SW'): precision += 0.5 found = 0.5 elif balloonExt.tailDirection == 'SW' and (balloonMatchGT.tailDirection == 'W' or balloonMatchGT.tailDirection == 'S'): precision += 0.5 found = 0.5 else: precision += 0#nbWrong += 1 found = 0 if verbose: if found == 1: print 'Matching',balloonExt.tailDirection,'for',balloonExt.BdB,'and',balloonMatchGT.BdB elif found == 0.5: print 'Found 50%',balloonExt.tailDirection,'!=',balloonMatchGT.tailDirection ,'between',balloonExt.BdB,'and', balloonMatchGT.BdB,'in',f plt.figure() plt.imshow(balloonExt.thumbnail) plt.show() else: print 'Found 0%',balloonExt.tailDirection,'!=',balloonMatchGT.tailDirection ,'between',balloonExt.BdB,'and', balloonMatchGT.BdB,'in',f plt.figure() plt.imshow(balloonExt.thumbnail) plt.show() nb += 1 #Get number of balloons nbBalloonsFromExtractor = len(balloonsFromExtractor) nbBalloonsFromGroundtruth = len(balloonsFromGroundtruth) #IF no balloon to find and no balloon found then return max score if nbBalloonsFromExtractor == 0 and nbBalloonsFromGroundtruth == 0: return 1,1,1 else: #Avoid division by zero if nbBalloonsFromGroundtruth == 0: nbBalloonsFromGroundtruth = 1 elif nbBalloonsFromExtractor == 0: nbBalloonsFromExtractor = 1 return float(recall)/nbBalloonsFromGroundtruth,float(precision)/nbBalloonsFromGroundtruth, nbBalloonsFromExtractor #return recall, precision