def calcUVXYZ(pxpts, hmatrix, camEnv): # xyzline (list): Line length (xyz) # xyzpts (list): XYZ coordinates of lines # pxline (list): Line length (px) # pxpts (list): UV coordinates of lines invprojvars = CamEnv.setProjection(camEnv.getDEM(), camEnv._camloc, camEnv._camDirection, camEnv._radCorr, camEnv._tanCorr, camEnv._focLen, camEnv._camCen, camEnv._refImage) # Calculate homography-corrected pts if desired # if hmatrix is not None: # print 'Correcting for camera motion' # pxpts = Velocity.apply_persp_homographyPts(pxpts, hmatrix, inverse=True) # Re-format pixel point coordinates pxpts = np.squeeze(pxpts) # Create OGR pixl line object and extract length pxline = getOGRLine(pxpts) print 'Line contains %i points' % (pxline.GetPointCount()) pxline = pxline.Length() print 'Line length: %d px' % (pxline) if invprojvars is not None: # Get xyz coordinates with inverse projection xyzpts = projectUV(pxpts, invprojvars) # Create ogr line object xyzline = getOGRLine(xyzpts) xyzline = xyzline.Length() print 'Line length: %d m' % (xyzline) return [[xyzline, xyzpts], [pxline, pxpts]] else: # Return pixel coordinates only return [[None, None], [pxline, pxpts]]
def calcManualArea(img, imn, hmatrix=None, pxplot=None, invprojvars=None): '''Manually define an area in a given image. User input is facilitated through an interactive plot to click around the area of interest. XYZ areas are calculated if a set of inverse projection variables are given. Args img (arr): Image array (for plotting the image). imn (str): Image name pxplot (list): Plotting extent for manual area definition invprojvars (list): Inverse projection variables Returns xyzarea (list): Sum of total detected areas (xyz) xyzpts (list): XYZ coordinates of detected areas pxextent (list): Sum of total detected areas (px) pxpts (list): UV coordinates of detected areas ''' #Initialise figure window and plot image fig=plt.gcf() fig.canvas.set_window_title(imn + ': Click around region. Press enter ' 'to record points.') plt.imshow(img, origin='upper', cmap='gray') #Set plotting extent if required if pxplot is not None: plt.axis([pxplot[0],pxplot[1], pxplot[2],pxplot[3]]) #Manual input of points from clicking on plot using pyplot.ginput rawpx = plt.ginput(n=0, timeout=0, show_clicks=True, mouse_add=1, mouse_pop=3, mouse_stop=2) print('\n' + imn + ': you clicked ' + str(len(rawpx)) + ' points') #Show plot plt.show() plt.close() #Convert coordinates to array pxpts=[] for i in rawpx: pxpts.append([[i[0],i[1]]]) pxpts.append([[rawpx[0][0],rawpx[0][1]]]) pxpts=np.asarray(pxpts) #Calculate homography-corrected pts if desired if hmatrix is not None: print('Correcting for camera motion') pxpts = Velocity.apply_persp_homographyPts(pxpts, hmatrix, inverse=True) #Create polygon if area has been recorded try: #Create geometry pxpoly=getOGRArea(pxpts.squeeze()) #Calculate area of polygon area pxextent = pxpoly.Area() #Create zero object if no polygon has been recorded except: pxextent = 0 print('Total extent: ' + str(pxextent) + ' px (out of ' + str(img.shape[0]*img.shape[1]) + ' px)') #Convert pts list to array pxpts = np.array(pxpts) pxpts = np.squeeze(pxpts) if invprojvars is not None: #Get xyz coordinates with inverse projection xyzpts=projectUV(pxpts, invprojvars) #Calculate area of xyz polygon xyzarea = getOGRArea(xyzpts) xyzarea=xyzarea.GetArea() #Return XYZ and pixel areas print('Total area: ' + str(xyzarea) + ' m') return [[[xyzarea], [xyzpts]], [[pxextent], [pxpts]]] #Return pixel areas only else: return [[None, None], [pxextent, pxpts]]
def calcAutoArea(img, imn, colourrange, hmatrix=None, threshold=None, invprojvars=None): '''Detects areas of interest from a given image, and returns pixel and xyz areas along with polygon coordinates. Detection is performed from the image using a predefined RBG colour range. The colour range is then used to extract pixels within that range using the OpenCV function inRange. If a threshold has been set (using the setThreshold function) then only nth polygons will be retained. XYZ areas and polygon coordinates are only calculated when a set of inverse projection variables are provided. Args img (arr): Image array imn (str): Image name colourrange (list): RBG colour range for areas to be detected from threshold (int): Threshold number of detected areas to retain invprojvars (list): Inverse projection variables Returns xyzarea (list): Sum of total detected areas (xyz) xyzpts (list): XYZ coordinates of detected areas pxextent (list): Sum of total detected areas (px) pxpts (list): UV coordinates of detected areas ''' #Get upper and lower RBG boundaries from colour range upper_boundary = colourrange[0] lower_boundary = colourrange[1] #Transform RBG range to array upper_boundary = np.array(upper_boundary, dtype='uint8') lower_boundary = np.array(lower_boundary, dtype='uint8') #Extract extent based on RBG range mask = cv2.inRange(img, lower_boundary, upper_boundary) # #Speckle filter to remove noise - needs fixing # mask = cv2.filterSpeckles(mask, 1, 30, 2) #Polygonize extents using OpenCV findContours function polyimg, line, hier = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) print('\nDetected ' + str(len(line)) + ' regions in ' + str(imn)) #Append all polygons from the polys list that have more than #a given number of points rawpx = [] for c in line: if len(c) >= 40: rawpx.append(c) #If threshold has been set, only keep the nth longest polygons if threshold is not None: if len(rawpx) >= threshold: rawpx.sort(key=len) rawpx = rawpx[-(threshold):] print('Kept ' + str(len(rawpx)) + ' regions') #Calculate homography-corrected pts if desired if hmatrix is not None: print('Correcting for camera motion') pxpts=[] for i in rawpx: corr = Velocity.apply_persp_homographyPts(i, hmatrix, inverse=True) pxpts.append(corr) else: pxpts=rawpx #Calculate areas pxextent=[] for p in range(len(pxpts)): try: #Create geometry pxpoly=getOGRArea(pxpts[p].squeeze()) #Calculate area of polygon area pxextent.append(pxpoly.Area()) #Create zero object if no polygon has been recorded except: pxextent = 0 print ('Total extent: ' + str(sum(pxextent)) + ' px (out of ' + str(img.shape[0]*img.shape[1]) + ' px)') #Get xyz coordinates with inverse projection if invprojvars is not None: xyzpts=[] xyzarea=[] for i in pxpts: #Inverse project points proj=projectUV(i, invprojvars) xyzpts.append(proj) #Get areas for xyz polygons ogrpol = getOGRArea(proj) xyzarea.append(ogrpol.GetArea()) print('Total area: ' + str(sum(xyzarea)) + ' m') #Return XYZ and pixel areas return [[xyzarea, xyzpts], [pxextent, pxpts]] else: #Return pixel areas only return [[None, None], [pxextent, pxpts]]
def verifyAreas(self, areas, invprojvars): '''Method to manually verify all polygons in images. Plots sequential images with detected polygons and the user manually verifies them by clicking them. Args area (list): XYZ and UV area information invprojvars (list): Inverse projection variables Returns verified (list): Verified XYZ and UV area information ''' #Create output verified = [] #Get UV point coordinates uvpts=[item[1][1] for item in areas] #Verify pixel polygons in each image for i in range(len(uvpts)): #Call corrected/uncorrected image if self._calibFlag is True: img1=self._imageSet[i].getImageCorr(self._camEnv.getCamMatrixCV2(), self._camEnv.getDistortCoeffsCV2()) else: img1=self._imageSet[i].getImageArray() #Get image name imn=self._imageSet[i].getImageName() #Verify polygons img2 = np.copy(img1) if 1: print('\nVerifying detected areas from ' + str(imn)) #Set up empty output list verf = [] #Function for click verification within a plot def onpick(event): #Get XY coordinates for clicked point in a plot v = [] thisline = event.artist xdata = thisline.get_xdata() ydata = thisline.get_ydata() #Append XY coordinates for x,y in zip(xdata,ydata): v.append([x,y]) v2=np.array(v, dtype=np.int32).reshape((len(xdata)),2) verf.append(v2) #Verify extent if XY coordinates coincide with a #detected area ind=event.ind print ('Verified extent at ' + str(np.take(xdata, ind)[0]) + ', ' + str(np.take(ydata, ind)[0])) #Plot image fig, ax1 = plt.subplots() fig.canvas.set_window_title(imn + ': Click on valid areas.') ax1.imshow(img2, cmap='gray') #Chane plot extent if pxplot variable is present if self._pxplot is not None: ax1.axis([self._pxplot[0],self._pxplot[1], self._pxplot[2],self._pxplot[3]]) #Plot all detected areas for a in uvpts[i]: x=[] y=[] for b in a: for c in b: x.append(c[0]) y.append(c[1]) line = Line2D(x, y, linestyle='-', color='y', picker=True) ax1.add_line(line) #Verify extents using onpick function fig.canvas.mpl_connect('pick_event', onpick) #Show plot plt.show() plt.close() #Append all verified extents vpx=[] vpx=verf #Get areas of verified extents h = img2.shape[0] w = img2.shape[1] px_im = Image.new('L', (w,h), 'black') px_im = np.array(px_im) cv2.drawContours(px_im, vpx, -1, (255,255,255), 4) for p in vpx: cv2.fillConvexPoly(px_im, p, color=(255,255,255)) output = Image.fromarray(px_im) pixels = output.getdata() values = [] for px in pixels: if px > 0: values.append(px) pxext = len(values) print('Total verified extent: ' + str(pxext)) #Get xyz coordinates with inverse projection if invprojvars is not None: vxyzpts=[] vxyzarea=[] for i in vpx: #Inverse project points proj=projectUV(i, invprojvars) vxyzpts.append(proj) ogrpol = getOGRArea(proj) vxyzarea.append(ogrpol.GetArea()) print('Total verified area: ' + str(sum(vxyzarea)) + ' m') verified.append([[pxext, vpx],[vxyzarea, vxyzpts]]) #Clear memory self._imageSet[i].clearImage() self._imageSet[i].clearImageArray() #Rewrite verified area data return verified
#Define camera environment tu1cam = CamEnv(tu1camenv) #Get DEM from camera environment dem = tu1cam.getDEM() #Get inverse projection variables through camera info invprojvars = setProjection(dem, tu1cam._camloc, tu1cam._camDirection, tu1cam._radCorr, tu1cam._tanCorr, tu1cam._focLen, tu1cam._camCen, tu1cam._refImage) #Show GCPs tu1cam.showGCPs() #Inverse project image coordinates using function from CamEnv object tu1_xyz = projectUV(tu1_xy, invprojvars) print '\n\n' + str(len(tu1_xyz)) + ' locations for calving events georectified' #----------------------- Plot xyz location on DEM ------------------------- print '\n\nPLOTTING XYZ CALVING LOCATIONS' #Boolean flags (True/False) save=True #Save plot? show=True #Show plot? #Retrieve DEM from CamEnv object demobj=tu1cam.getDEM()
def calcManualLine(img, imn, hmatrix=None, invprojvars=None): """Manually define a line in a given image to produce XYZ and UV line length and corresponding coordinates. Lines are defined through user input by clicking in the interactive image plot. This primarily operates via the pyplot.ginput function which allows users to define coordinates through plot interaction. If inverse projection variables are given, XYZ lines and coordinates are also calculated. :param img: Image array for plotting. :type img: arr :param imn: Image name :type imn: str :param hmatrix: Homography matrix, default to None :type hmatrix: arr, optional :param invprojvars: Inverse projection variables [X,Y,Z,uv0], default to None :type invprojvars: list, optional :returns: Four list elements containing: line length in xyz (list), xyz coordinates of lines (list), line length in pixels (list), and uvcoordinates of lines (list) :rtype: list """ #Initialise figure window fig = plt.gcf() fig.canvas.set_window_title(imn + ': Define line. ' 'Press enter to record points.') #Plot image plt.imshow(img, origin='upper', cmap='gray') rawpx = plt.ginput(n=0, timeout=0, show_clicks=True, mouse_add=1, mouse_pop=3, mouse_stop=2) print('\nYou clicked ' + str(len(rawpx)) + ' points in image ' + str(imn)) #Show plot plt.show() plt.close() #Convert coordinates to array pxpts = [] for i in rawpx: pxpts.append([[i[0], i[1]]]) pxpts = np.asarray(pxpts) #Calculate homography-corrected pts if desired if hmatrix is not None: print('Correcting for camera motion') pxpts = Velocity.apply_persp_homographyPts(pxpts, hmatrix, inverse=True) #Re-format pixel point coordinates pxpts = np.squeeze(pxpts) #Create OGR pixl line object and extract length pxline = getOGRLine(pxpts) print('Line contains ' + str(pxline.GetPointCount()) + ' points') pxline = pxline.Length() print('Line length: ' + str(pxline) + ' px') if invprojvars is not None: #Get xyz coordinates with inverse projection xyzpts = projectUV(pxpts, invprojvars) #Create ogr line object xyzline = getOGRLine(xyzpts) xyzline = xyzline.Length() print('Line length: ' + str(xyzline) + ' m') return [[xyzline, xyzpts], [pxline, pxpts]] else: #Return pixel coordinates only return [[None, None], [pxline, pxpts]]