def mergeAllLines(dirPathLines, epsgValue):
    """
    mergeAllLines.
       
    :param dirPathLines: (String) path.
	:param epsgValue: (int) epsg code.
    :returns none: None.
    """

    crutils.printLogMsg(crglobals.SEPARATOR_MSG)
    lineask = []
    for file in os.listdir(dirPathLines):
        if file.endswith(".shp"):
            if file.startswith("mosaic"):
                filesm = os.path.join(dirPathLines, file)
                crutils.printLogMsg(crglobals.OK_MSG + 'Reading file: %s ' %
                                    (filesm))
                lineask.append(gpd.GeoDataFrame.from_file(filesm))

    mergedLinesArray = []
    a = 0
    for i in lineask:
        mergedLinesArray.append(lineask[a])
        a += 1

    result = pd.concat(mergedLinesArray, axis=0)

    result.to_file(driver='ESRI Shapefile',
                   filename=os.path.join(dirPathLines, 'merged_lines.shp'))
    crutils.printLogMsg(crglobals.DONE_MSG + 'Save merged lines !!')

    crutils.printLogMsg(crglobals.START_MSG +
                        'Merge all Points from merged lines')

    crsEpsgId = {'init': 'epsg:' + str(epsgValue)}
    col = result.columns.tolist()[:-1]
    #[0:5]
    #print(col)
    nodes = gpd.GeoDataFrame(crs=crsEpsgId, columns=col)
    # extraction of nodes and attribute values nouveau GeoDataFrame
    for index, row in result.iterrows():
        for pt in list(row['geometry'].coords):
            #nodes = nodes.append({'col': int(row['col']), 'row': int(row['row']),  'distance':row['distance'],'id':row['id'], 'geometry':Point(pt) },ignore_index=True)
            nodes = nodes.append(
                {
                    'col': str(row['col']),
                    'row': str(row['row']),
                    'colrow': str(row['col']) + '_' + str(row['row']),
                    'id': str(row['id']),
                    'geometry': Point(pt)
                },
                ignore_index=True)
    nodes.head(5)

    nodes.to_file(driver='ESRI Shapefile',
                  filename=os.path.join(dirPathLines, 'merged_points.shp'))
    crutils.printLogMsg(crglobals.DONE_MSG + 'Save merged points !!')

    return 1
def mergeAllPoints(dirPathLines, epsgValue):
    """
	mergeAllPoints.
	
	:param dirPathLines: (text) path lines directory.
	:param epsgValue: (int) epsg code.
	:returns None: (None).
	"""

    #mosaic-cl_17-rw_4_points
    crsEpsgId = {'init': 'epsg:' + str(epsgValue)}

    mergePointsArray = []
    for file in os.listdir(dirPathLines):
        if file.endswith(".geojson"):
            if file.startswith("mosaic"):
                if file.find("points") != -1:
                    filesm = os.path.join(dirPathLines, file)
                    #print(filesm)
                    try:
                        mergePointsArray.append(
                            gpd.GeoDataFrame.from_file(filesm))
                    except KeyError:
                        crutils.printLogMsg('In file: %s' % (filesm))
                        crutils.printLogMsg(
                            crglobals.FAIL_MSG +
                            'Points file without geometry column !')

    #print(mergePointsArray)
    mergedLinesArray = []
    a = 0
    for i in mergePointsArray:
        mergedLinesArray.append(mergePointsArray[a])
        a += 1

    result = pd.concat(mergedLinesArray, axis=0)

    result.to_file(driver='ESRI Shapefile',
                   filename=os.path.join(dirPathLines, 'merged_rawpoints.shp'))
    crutils.printLogMsg(crglobals.DONE_MSG + 'Save merged raw points !!')

    return 1
def cropRowsMain():
    
    """
    cropRowsMain.
    
    :param self: no input params
    :returns: None
    """

    if len(sys.argv)<2:
        printLogMsg(crglobals.SEPARATOR_MSG)
        print(crglobals.ERROR_MSG+"Fatal: You forgot to include the crop rows project file on the command line.")
        print("Usage: python %s <croprowsproject.xml>" % sys.argv[0])
        printLogMsg(crglobals.SEPARATOR_MSG)
        print(crglobals.HELP_MSG)
        sys.exit(1)
    
    if(sys.argv[1]=='-h'):
        print(crglobals.HELP_MSG)
        sys.exit(1)
    ######################################################
    ##Define processing vars
    ######################################################

    if len(sys.argv)>2:
        if(sys.argv[2]=='-p'):
            crglobals.PROCESSING_MODE = 'parallel'
        if(sys.argv[2]=='-s'):
            crglobals.PROCESSING_MODE = 'serial'
        if(sys.argv[2]=='-debug'):
            crglobals.DEBUGMODE = False
        if(sys.argv[2]=='-t'):
            crglobals.DEF_TILESIZE_M = int(sys.argv[3])
        if(sys.argv[2]=='-h'):
            print(crglobals.HELP_MSG)
               
    printLogMsg(crglobals.SEPARATOR_MSG)
    printLogMsg('Number of arguments: %s arguments.' % (len(sys.argv)) )
    printLogMsg('Argument List: %s arguments.' % str(sys.argv) )
    printLogMsg('Processing Mode : %s ' % str(crglobals.PROCESSING_MODE) )
    

    #imagePathResults = "../orthomosaics/"
    #shared folder for croprows cli
    imagePathResults = "orthomosaics/"
    cropRowsProjectFile =  sys.argv[1]

    #Read Crop Rows Project Config File
    crFileObject = croprowsFileReader(os.path.join(imagePathResults,cropRowsProjectFile)) 
    fileNameValue=crFileObject['filename']
    imageDimensionsValue=crFileObject['image_dimensions']
    imageOriginValue=crFileObject['image_origin']
    pixelSizeValue=crFileObject['pixel_size']
    imageExtentsValue=crFileObject['image_extents']
    epsgValue=crFileObject['epsg']
    projWKTValue=crFileObject['projwtk']
    seedValue=crFileObject['seed']
    maskValue=crFileObject['mask']
    prjValue=crFileObject['prj']

    ####################################################
    ## Crop Rows Tiles Generation
    ####################################################
    
    ## TODO: Perform a Parallel task 

    #Config tiles generation
    cfgTilesGenerator = [
        imagePathResults, 
        fileNameValue, 
        imageDimensionsValue,
        imageOriginValue,
        pixelSizeValue,
        imageExtentsValue,
        crglobals.DEF_TILESIZE_M,
        epsgValue,
        projWKTValue,
        prjValue]
    #Exec tilesGeneration task 

    #Create a new tilesGenerator Instance
    tilesGenerator = CropRowsTilesGenerator()
    tilesGenerator.tilesGeneration(cfgTilesGenerator)
    tilesDirName, nCols , nRows = tilesGenerator.getTilesGenerationGlobals()
    printLogMsg('->tilesDirName: %s \n->nRows: %s \n->nCols: %s ' % (tilesDirName,nRows,nCols))

    #Config angles generator
    cfgAnglesGenerator = [
        tilesDirName,
        nCols,
        nRows,
        seedValue,
        crglobals.SEED_SPAN
    ]
    #Exec anglesGeneration task
    anglesGenerator = CropRowsAnglesGenerator()
    anglesGenerator.anglesGeneration(cfgAnglesGenerator)
    anglesFoundArray, angleMean, angleSd = anglesGenerator.getAnglesGeneratorGlobals()  
    #Angles found 
    printLogMsg(crglobals.SEPARATOR_MSG)
    printLogMsg(anglesFoundArray)
    printLogMsg(crglobals.OK_MSG+'Mean Angle: %s' % (angleMean))
    printLogMsg(crglobals.OK_MSG+'Std Angle: %s' % (angleSd))
    printLogMsg(crglobals.SEPARATOR_MSG)

    #Generate Lines Config
    cfgLinesGenerator =[
        tilesDirName,
        angleMean,
        pixelSizeValue,
        imageExtentsValue,
        epsgValue,
        crglobals.DEF_TILESIZE_M,
        nCols,
        nRows
    ]
    #Exec generateLinesAll task
    generateCropRowsLinesAll(cfgLinesGenerator)

    cfgPostProcessingLines =[
        tilesDirName,
        epsgValue,
        nCols,
        nRows,
        imagePathResults+maskValue,
        seedValue
    ]
    
    #exec Post processing Lines task
    postProcessingLines(cfgPostProcessingLines)

    endTime = time.time()
    elapsedTime = endTime - startTime

    printLogMsg(crglobals.SEPARATOR_MSG)
    printLogMsg(crglobals.DONEEND_MSG+"Total Processing Time: "+str(round(elapsedTime,2)) + " seconds")
    printLogMsg(crglobals.DONEEND_MSG+'Data processed in %s mode ' % str(crglobals.PROCESSING_MODE) )
    printLogMsg(crglobals.SEPARATOR_MSG)
    printLogMsg(crglobals.BANNER_DONE)
    if(crglobals.DEBUGMODE==False):
        print(crglobals.DONE_MSG+'CROP ROWS GENERATION')
        print(crglobals.DONEEND_MSG+"Total Processing Time: "+str(round(elapsedTime,2)) + " seconds")
def postProcessingLines(cfgPostProcessingLines):
    """
	postProcessingLines.
	
	:param cfgPostProcessingLines: (Array) lines postprocessing config array.
	:returns: none.
    """

    ##Extend All Lines
    ##print('=========================================')
    ##print('Extend all Lines and Clip by Mask')
    tilesDirName = cfgPostProcessingLines[0]
    epsgValue = cfgPostProcessingLines[1]
    nCols = cfgPostProcessingLines[2]
    nRows = cfgPostProcessingLines[3]
    imagePathVectorMask = cfgPostProcessingLines[4]
    seedValue = cfgPostProcessingLines[5]

    #tilesDirName+'/'+crglobals.VECTORDIR+'/'+crglobals.OBJDIR
    obDir = os.path.join(tilesDirName, crglobals.VECTORDIR, crglobals.OBJDIR)

    startTime = time.time()
    ############################################################################################
    #Multiprocessing Task
    processingCores = (multiprocessing.cpu_count())
    crutils.printLogMsg(crglobals.CHECK_MSG + "Number of CPU cores: %s" %
                        (str(processingCores)))
    crutils.printLogMsg(crglobals.SEPARATOR_MSG)
    processingPool = multiprocessing.Pool(processes=(processingCores + 2))
    results = [
        processingPool.apply(extendAllLinesInParallel,
                             args=(
                                 tilesDirName,
                                 epsgValue,
                                 i,
                                 j,
                                 imagePathVectorMask,
                                 seedValue,
                             )) for i in range(nCols) for j in range(nRows)
    ]
    #print(results)
    processingPool.close()
    #while len(active_children()) > 1:
    #	print('Still active children process for -> extendAllLinesInParallel')
    #	time.sleep(0.5)
    processingPool.join()
    ############################################################################################
    endTime = time.time()
    elapsedTime = endTime - startTime
    crutils.printLogMsg(crglobals.SEPARATOR_MSG)
    # print total image generation time
    crutils.printLogMsg(crglobals.DONE_MSG +
                        "extendAllLinesInParallel generation")
    crutils.printLogMsg(crglobals.DONEEND_MSG + "Total processing time: " +
                        str(round(elapsedTime, 2)) + " seconds")
    crutils.printLogMsg(crglobals.SEPARATOR_MSG)

    #Old way: no parallelized task
    #extendAllLines(tilesDirName,epsgValue,nCols,nRows,imagePathVectorMask,seedValue)

    ##Merge All Lines
    crutils.printLogMsg(crglobals.SEPARATOR_MSG)
    crutils.printLogMsg(crglobals.START_MSG + 'Merge All Lines')
    mergeAllLines(obDir, epsgValue)

    ##Extend All Lines
    crutils.printLogMsg(crglobals.SEPARATOR_MSG)
    crutils.printLogMsg(crglobals.START_MSG + 'Extend All Lines')
    extendAllMergedLines(obDir, imagePathVectorMask, epsgValue)

    ##Merge All Points
    crutils.printLogMsg(crglobals.SEPARATOR_MSG)
    crutils.printLogMsg(crglobals.START_MSG + 'Merge All Points')
    mergeAllPoints(obDir, epsgValue)

    return 1
def extendAllLinesInParallel(tilesDirName, epsgValue, iCols, jRows,
                             maskVectorFile, seedValue):
    """
	extendAllLinesInParallel.
	
	:param tilesDirName: (String) tile directory name.
	:param epsgValue: (String) code for refrerence system.
	:param iCols: (int) current column.
	:param jRows: (int) current row.
	:param maskVectorFile: (String) mask file name.
	:param seedValue: (int) seed for crop rows orientation.
	:returns none: None.
    """

    crutils.printLogMsg(crglobals.SEPARATOR_MSG)
    crutils.printLogMsg(
        crglobals.WORKER_MSG +
        "extendAllLinesInParallel -> Processing Tile %s , %s " %
        (str(iCols), str(jRows)))
    processName = multiprocessing.current_process().name
    crutils.printLogMsg(crglobals.START_MSG + 'Process name: %s ' %
                        (processName))
    crutils.printLogMsg(crglobals.START_MSG + "Parent processs: %s" %
                        (str(os.getppid())))
    crutils.printLogMsg(crglobals.START_MSG + "Process id: %s" %
                        (str(os.getpid())))

    crutils.printLogMsg(crglobals.CHECK_MSG + 'tilesDirName: %s' %
                        (tilesDirName))
    crutils.printLogMsg(crglobals.OK_MSG + 'EPSG: %s' % (epsgValue))
    crutils.printLogMsg(crglobals.OK_MSG + 'iCols: %s' % (iCols))
    crutils.printLogMsg(crglobals.OK_MSG + 'jRows: %s' % (jRows))

    dirNameVectorResults = os.path.join(tilesDirName, crglobals.VECTORDIR)
    dirNameVectorObjResults = os.path.join(dirNameVectorResults,
                                           crglobals.OBJDIR)

    crutils.printLogMsg(crglobals.OK_MSG + 'Vector dir: %s' %
                        (dirNameVectorResults))
    crutils.printLogMsg(crglobals.OK_MSG + 'Vector dir Obj: %s' %
                        (dirNameVectorObjResults))
    crutils.printLogMsg(crglobals.OK_MSG + 'Mask File: %s' % (maskVectorFile))

    boundsVectorFile = crglobals.PICNAME + "-" + crglobals.COLPREFIX + str(
        iCols) + "-" + crglobals.ROWPREFIX + str(jRows) + crglobals.GEOJSON_EXT
    linesVectorFile = crglobals.PICNAME + "-" + crglobals.COLPREFIX + str(
        iCols) + "-" + crglobals.ROWPREFIX + str(
            jRows) + "_" + crglobals.VECTORLINES + crglobals.GEOJSON_EXT
    crutils.printLogMsg(crglobals.OK_MSG + "Bounds File : %s" %
                        (boundsVectorFile))
    crutils.printLogMsg(crglobals.OK_MSG + "Lines File: %s" %
                        (linesVectorFile))

    crutils.printLogMsg(crglobals.CHECK_MSG + 'File %s is correct !' %
                        (linesVectorFile))

    extendLinesGeom(iCols, jRows, epsgValue, dirNameVectorResults,
                    dirNameVectorObjResults, boundsVectorFile, linesVectorFile,
                    maskVectorFile, seedValue)
    crutils.printLogMsg(crglobals.SEPARATOR_MSG)

    return 1
def extendAllMergedLines(dirPathLines, vectorMask, epsgValue):
    """
    extendAllMergedLines.
       
    :param dirPathLines: (text) path
	:param vectorMask: (text) path
	:param epsgValue: (text) epsg value
    :returns: OpenCV version.
    """

    crsEpsgId = {'init': 'epsg:' + str(epsgValue)}

    crutils.printLogMsg(crglobals.OK_MSG + 'Path Lines: %s' % (dirPathLines))
    crutils.printLogMsg(crglobals.OK_MSG + 'Mask: %s' % (vectorMask))
    crutils.printLogMsg(crglobals.OK_MSG + 'EPSG: %s' % (epsgValue))

    #input merged line file
    fileNameMergedLines = 'merged_lines.shp'
    mergedLinesGeoDataFrame = gpd.GeoDataFrame.from_file(
        os.path.join(
            dirPathLines,
            fileNameMergedLines))  #dirPathLines+'/'+fileNameMergedLines)
    #input mask polygon file
    boundsMaskGeoDataFrame = gpd.GeoDataFrame.from_file(vectorMask)

    longLinesArray = []
    idLongLinesArray = []
    for x in range(0, len(mergedLinesGeoDataFrame.geometry)):
        linea_bx = (list(mergedLinesGeoDataFrame.geometry[x].coords))
        extrapoledLine = getExtrapoledLine(*linea_bx[-2:])
        idLongLinesArray.append(x)
        longLinesArray.append(extrapoledLine)

    dataFrameLongLines = pd.DataFrame({'id': idLongLinesArray})
    longLinesGeoDataFrame = gpd.GeoDataFrame(dataFrameLongLines,
                                             crs=crsEpsgId,
                                             geometry=longLinesArray)
    longLinesFileName = os.path.join(
        dirPathLines,
        'merged_lines_long.shp')  #dirPathLines+'/'+'merged_lines_long.shp'
    longLinesGeoDataFrame.to_file(driver='ESRI Shapefile',
                                  filename=longLinesFileName)
    crutils.printLogMsg(crglobals.DONE_MSG + 'Generated long lines !')

    #######################################################################################
    #Get the convex hull lines
    convexHullFromBoundsMask = boundsMaskGeoDataFrame.convex_hull.iloc[0]
    x, y = convexHullFromBoundsMask.exterior.xy
    pointsConvexHullFromBoundsMaskArray = np.array(list(zip(x, y)))
    minBBoxRect = imboundrect.minimum_bounding_rectangle(
        pointsConvexHullFromBoundsMaskArray)
    polygonOMBB = Polygon(
        [minBBoxRect[0], minBBoxRect[1], minBBoxRect[2], minBBoxRect[3]])
    #######################################################################################
    #cut lines by ombb
    #update applying buffer. it fix some strange bug at some corner lines
    geoDataFrameLineCuttedByBoxBuffer = (longLinesGeoDataFrame.intersection(
        polygonOMBB.buffer(20)))
    dataFrameLineCuttedByBoxDf = pd.DataFrame({
        'id':
        idLongLinesArray,
        'len':
        geoDataFrameLineCuttedByBoxBuffer.length
    })
    geoDataFrameLinesCuttedByBox = gpd.GeoDataFrame(
        dataFrameLineCuttedByBoxDf,
        crs=crsEpsgId,
        geometry=geoDataFrameLineCuttedByBoxBuffer)
    mergedLinesCuttedByOMBBPolygonFile = os.path.join(
        dirPathLines, 'merged_lines_long_cut_ombb.shp'
    )  #dirPathLines+'/'+'merged_lines_long_cut_ombb.shp'
    geoDataFrameLinesCuttedByBox.to_file(
        driver='ESRI Shapefile', filename=mergedLinesCuttedByOMBBPolygonFile)
    crutils.printLogMsg(crglobals.DONE_MSG + 'Cut long lines by OMBB bounds !')

    #######################################################################################
    projectDistance = 1
    #enumerate lines in spatial order
    angle = crutils.getAzimuth(
        (geoDataFrameLinesCuttedByBox.geometry[0].coords[0][0]),
        (geoDataFrameLinesCuttedByBox.geometry[0].coords[0][1]),
        (geoDataFrameLinesCuttedByBox.geometry[0].coords[1][0]),
        (geoDataFrameLinesCuttedByBox.geometry[0].coords[1][1]))
    anglep = (angle + 270)
    #search for the closest geometry line to temporal point
    temporalXpoint = (geoDataFrameLinesCuttedByBox.geometry[0].centroid.x
                      ) + np.sin(np.deg2rad(anglep)) * 5000
    temporalYpoint = (geoDataFrameLinesCuttedByBox.geometry[0].centroid.y
                      ) + np.cos(np.deg2rad(anglep)) * 5000
    temporalExternalPoint = Point((temporalXpoint, temporalYpoint))
    crutils.printLogMsg(crglobals.DONE_MSG + 'Generate a Temporal Point')
    #print(temporalExternalPoint)
    tmpLineDistance = []
    for i in range(len(geoDataFrameLinesCuttedByBox)):
        distanceCalculated = (temporalExternalPoint.distance(
            geoDataFrameLinesCuttedByBox.geometry[i].centroid))
        tmpLineDistance.append(distanceCalculated)
        #print("i: %s -> distanceCalculated: %s -> %s" % (str(i), str(distanceCalculated) , str(geoDataFrameLinesCuttedByBox.geometry[i])   ))
    minelem = np.argmin(tmpLineDistance)
    crutils.printLogMsg(crglobals.DONE_MSG + "Found a closest line id: %s" %
                        (str(minelem)))
    #######################################################################################
    #Calc Distances using the closest line found
    xp = (geoDataFrameLinesCuttedByBox.geometry[minelem].centroid.x) + np.sin(
        np.deg2rad(anglep)) * projectDistance
    yp = (geoDataFrameLinesCuttedByBox.geometry[minelem].centroid.y) + np.cos(
        np.deg2rad(anglep)) * projectDistance
    externalPoint = Point((xp, yp))
    #print(externalPoint)

    geoDistance = []
    index = []

    for i in range(len(geoDataFrameLinesCuttedByBox)):
        #print('-> %s' % ( str( i)))
        distanceCalculated = (externalPoint.distance(
            geoDataFrameLinesCuttedByBox.geometry[i].centroid))
        geoDistance.append(distanceCalculated)
        #print(distanceCalculated)
        index.append(i)

    dataFrameLineCuttedByBoxBuffer = pd.DataFrame({
        'len':
        geoDataFrameLineCuttedByBoxBuffer.length,
        'geo_dist':
        geoDistance,
        'idx':
        index
    })
    geoDataFrameLinesCuttedByBox = gpd.GeoDataFrame(
        dataFrameLineCuttedByBoxBuffer,
        crs=crsEpsgId,
        geometry=geoDataFrameLineCuttedByBoxBuffer)

    mergedLongLinesCuttedByOMBwDistFileName = os.path.join(
        dirPathLines, 'merged_lines_long_cut_ombb_wdist.shp'
    )  #dirPathLines+'/'+'merged_lines_long_cut_ombb_wdist.shp'
    geoDataFrameLinesCuttedByBox.to_file(
        driver='ESRI Shapefile',
        filename=mergedLongLinesCuttedByOMBwDistFileName)

    #######################################################################################
    #######################################################################################
    ############## FILTERING LINES LOOKING FOR CANDIDATES #################################
    #######################################################################################
    #######################################################################################

    sortedDistance = np.argsort(geoDistance).astype('int')
    idByGeo = [x for _, x in sorted(zip(sortedDistance, index))]

    newObjDistancesSorted = np.sort(geoDistance)

    #Removing Adjacents and lines duplicates
    newObjDistancesSorted = crutils.removeAdjacentsInArray(
        newObjDistancesSorted)

    #print('====== new distances sorted =====')
    #print(newObjDistancesSorted)
    crutils.printLogMsg(crglobals.DONE_MSG + 'Candidate lines: %s ' %
                        str(len(newObjDistancesSorted)))

    ##Removing Closing Lines
    #pairsdistances = zip([0]+newObjDistancesSorted, newObjDistancesSorted)

    #TODO: distancesFiltered
    #distancesFiltered = [pair[1] for pair in pairsdistances if abs(pair[0]-pair[1]) >=0.5 ]
    ###########################################
    ## OTRO APPROACH TO FIND DISTANCES

    groups, current_group, first = [], [], newObjDistancesSorted[0]
    for item in newObjDistancesSorted:
        # Check if this element falls under the current group
        if item - first <= 1.3:
            current_group.append(item)
        else:
            # If it doesn't, create a new group and add old to the result
            groups.append(current_group[:])
            current_group, first = [item], item
        # Add the last group which was being gathered to the result
    groups.append(current_group[:])
    distancesFiltered = [np.max(item) for item in groups]

    #iter 1 removing proximal lines
    pairsdistances2 = zip([0] + distancesFiltered, distancesFiltered)
    distancesFiltered = [
        pair[1] for pair in pairsdistances2 if abs(pair[0] - pair[1]) >= 0.4
    ]

    #iter 2 removing proximal lines
    pairsdistances3 = zip([0] + distancesFiltered, distancesFiltered)
    distancesFiltered = [
        pair[1] for pair in pairsdistances3 if abs(pair[0] - pair[1]) >= 0.9
    ]  #>=0.8  -preff: 0.9

    ######################################3
    #print('====== distances filtered =====')
    #print(distancesFiltered)

    crutils.printLogMsg(crglobals.DONE_MSG +
                        'Resulting lines: %s ' % str(len(distancesFiltered)))

    #TODO: final

    #cut final lines by mask
    dataFrameCandidateLines = (geoDataFrameLinesCuttedByBox.intersection(
        boundsMaskGeoDataFrame.geometry.iloc[0]))

    candidateLinesFileName = os.path.join(
        dirPathLines,
        'candidate_lines.shp')  #dirPathLines+'/'+'candidate_lines.shp'

    dataFrameLineCuttedByMask = pd.DataFrame({
        'distance':
        dataFrameCandidateLines.length,
        'geo_dist':
        geoDistance,
        'idx':
        index
    })

    geoDataFrameLineCuttedByMask = gpd.GeoDataFrame(
        dataFrameLineCuttedByMask,
        crs=crsEpsgId,
        geometry=dataFrameCandidateLines)
    geoDataFrameLineCuttedByMask.to_file(driver='ESRI Shapefile',
                                         filename=candidateLinesFileName)

    #####################################
    ## NEW CROPROWS - GEOMETRY SEARCH
    #####################################

    #save candidateLinesbuffer
    candidateLinesBufferFileName = os.path.join(dirPathLines,
                                                'candidate_lines_buffer.shp')
    candidateLinesBuffer = geoDataFrameLineCuttedByMask.buffer(0.3)
    s = candidateLinesBuffer

    #ADDING FEATURE 3-9-2018
    #DISOLVE OVERLAPPING BUFFER POLYGONS
    #https://gis.stackexchange.com/questions/271733/geopandas-dissolve-overlapping-polygons/271735
    overlap_matrix = s.apply(lambda x: s.overlaps(x)).values.astype(int)
    n, ids = connected_components(overlap_matrix)
    df = gpd.GeoDataFrame({'geometry': s, 'group': ids}, crs=crsEpsgId)
    res = df.dissolve(by='group')
    res.to_file(driver='ESRI Shapefile', filename=candidateLinesBufferFileName)

    candidateLinesBufferCentroidFileName = os.path.join(
        dirPathLines, 'candidate_lines_buffer_centroid.shp')
    points = res.copy()
    points.geometry = res['geometry'].centroid
    points.crs = res.crs
    points.head()
    points.to_file(driver='ESRI Shapefile',
                   filename=candidateLinesBufferCentroidFileName)

    df_lines = dataFrameCandidateLines.geometry
    df_points = points.geometry
    #print(len(df_points))
    #print(len(df_lines))

    idClosestLineArr = []
    #find the closest candidate line to point
    for x in range(0, len(df_points)):
        minDistancePointLine = df_lines.distance(df_points[x]).min()
        allDistanceToLines = df_lines.distance(df_points[x])
        idClosestLine = np.where(allDistanceToLines == minDistancePointLine)[0]
        idClosestLineArr.append(idClosestLine[0])
        #print('centroid point: %s - id closest line: ' % (str(x)) , (str(idClosestLine))   )

    #print(idClosestLineArr)
    selcr = []
    for x in range(0, len(df_lines)):
        selcr = df_lines[idClosestLineArr]

    crf = 0
    geoidcr = []
    croprowLength = []

    for y in range(0, len(selcr)):
        #print(selcr.geometry.iloc[y])
        #print(selcr.geometry.iloc[y].length)
        croprowLength.append(selcr.geometry.iloc[y].length)
        geoidcr.append(crf)
        crf = crf + 1

    dataFrameCr = pd.DataFrame({
        'geometry': selcr,
        'crlen': croprowLength,
        'idg': geoidcr,
        'crg': 'Generated by Crop Rows Generator v1'
    })
    geoDataFrameCropRows = gpd.GeoDataFrame(dataFrameCr, crs=crsEpsgId)
    cropRowsFileNameByGeom = os.path.join(dirPathLines, 'croprows_lines.shp')
    geoDataFrameCropRows.to_file(driver='ESRI Shapefile',
                                 filename=str(cropRowsFileNameByGeom))

    ##EXPORT CROP ROWS RESULTS TO WGS84 SHP AND KML FORMATS
    crsExportID = {'init': 'epsg:' + str(crglobals.EXPORT_EPSG)}
    exportCropRowsShapeFile = os.path.join(
        os.path.dirname(os.path.dirname(dirPathLines)), crglobals.EXPORTDIR,
        'croprows_wgs84.shp')
    geoDataFrameCropRowsWGS84 = gpd.GeoDataFrame(dataFrameCr, crs=crsEpsgId)
    geoDataFrameCropRowsWGS84 = geoDataFrameCropRowsWGS84.to_crs(crsExportID)
    geoDataFrameCropRowsWGS84.to_file(driver='ESRI Shapefile',
                                      filename=str(exportCropRowsShapeFile))
    exportCropRowsShapeFileKML = os.path.join(
        os.path.dirname(os.path.dirname(dirPathLines)), crglobals.EXPORTDIR,
        'croprows_wgs84.kml')
    geoDataFrameCropRowsWGS84.to_file(driver='kml',
                                      filename=str(exportCropRowsShapeFileKML))
    crutils.printLogMsg(
        crglobals.DONE_MSG +
        'Exported Resulting Crop Rows to KML and SHP format in WGS84 CRS')

    cropRowsBufferFileName = os.path.join(dirPathLines,
                                          'croprows_lines_buffer.shp')
    cropRowsLinesBuffer = geoDataFrameCropRows.buffer(0.3)
    cropRowsLinesBufferGeoData = gpd.GeoDataFrame(crs=crsEpsgId,
                                                  geometry=cropRowsLinesBuffer)
    cropRowsLinesBufferGeoData.to_file(driver='ESRI Shapefile',
                                       filename=str(cropRowsBufferFileName))

    #####################################
    ## OLD CROPROWS - STAT SEARCH
    #####################################
    getIndexes = lambda x, xs: [
        i for (y, i) in zip(xs, range(len(xs))) if x == y
    ]
    cuttedLineArray = []
    #look for
    k = []
    flagCounter3 = 0
    for x in distancesFiltered:
        #print(distancesFiltered[i])
        #print(getIndexes(distancesFiltered[i],newobjdistances))
        k.append(getIndexes(distancesFiltered[flagCounter3], geoDistance)[0])
        flagCounter3 = flagCounter3 + 1

    #Reindex lines filtered
    index2 = []
    flagCounter2 = 0
    m = []
    j = 0
    croprowLength = []
    for x in k:
        m.append(dataFrameCandidateLines[k[j]])
        index2.append(flagCounter2)
        #line len for each geometry
        croprowLength.append(m[j].length)
        flagCounter2 += 1
        j = j + 1

    #print('index2:')
    #print(index2)
    #print('k')
    #print(k)
    #print('m')
    #print(m)

    sortdistance2 = np.argsort(distancesFiltered).astype('int')
    idByGeo2 = [x for _, x in sorted(zip(sortdistance2, index2))]

    #print('idByGeo2')
    #print(idByGeo2)

    crutils.printLogMsg(crglobals.DONE_MSG + 'Re-indexing candidate lines !')

    #Fix distances substracting projectDistance
    arrayDistances = np.array(distancesFiltered)
    #fixdist = arrayDistances - projectDistance
    crutils.printLogMsg(crglobals.DONE_MSG + 'Distances fixed !')

    #print(croprowLength)

    #fixdist
    dataFrameFixedLines = pd.DataFrame({
        'id': k,
        'geo_dist': arrayDistances,
        'idgeo': idByGeo2,
        'crlen': croprowLength
    })
    #dataFrameFixedLines = pd.DataFrame({  })
    geoDataFrameFixedLines = gpd.GeoDataFrame(dataFrameFixedLines,
                                              crs=crsEpsgId,
                                              geometry=m)
    geoDataFrameFixedLines.dropna()

    crutils.printLogMsg(crglobals.DONE_MSG + 'Result lines generated !')

    cropRowsLinesFileName = os.path.join(dirPathLines,
                                         'croprows_lines_stat.shp')
    geoDataFrameFixedLines.to_file(driver='ESRI Shapefile',
                                   filename=str(cropRowsLinesFileName))

    crutils.printLogMsg(crglobals.DONE_MSG +
                        'Writing file with resulting lines : %s ' %
                        (cropRowsLinesFileName))

    #saveResultXMLFile(cropRowsLinesFileName)
    resultingFiles = [
        cropRowsFileNameByGeom, cropRowsBufferFileName,
        exportCropRowsShapeFile, exportCropRowsShapeFileKML,
        str(epsgValue),
        str(len(newObjDistancesSorted)),
        str(len(distancesFiltered)), vectorMask
    ]
    saveResultXMLFile(resultingFiles)
    #saveResultXMLFile(cropRowsFileNameByGeom,cropRowsBufferFileName,exportCropRowsShapeFile,exportCropRowsShapeFileKML)

    #####################################

    return 1
def extendProcessing(boxGeoDataFrame, linesGeoDataFrame, epsgValue,
                     dirNameVectorObjResults, linesExtendedFileName,
                     vectorMask, col, row, seedValue):
    """
	extendProcessing.
	
	:param boxGeoDataFrame: (Box) box
	:param linesGeoDataFrame: (int) lines
	:param epsgValue: (int) spatial reference system
	:param dirNameVectorObjResults: (String) vector objects folder
	:param linesExtendedFileName: (String) lines extended file.
	:param seedValue: (int) seed for crop rows orientation.
	:returns none: None.
    """
    crsEpsgId = {'init': 'epsg:' + str(epsgValue)}

    longLinesArray = []
    idLongLinesArray = []
    cuttedLineArray = []
    newidcutedline = []
    newobjdistances = []
    distanceLinear = []
    index = []

    flagCounter = 0

    externalPoint = Point((0, 0))

    #Extrapolate lines
    for x in range(0, len(linesGeoDataFrame.geometry)):
        linea_bx = (list(linesGeoDataFrame.geometry[x].coords))
        extrapoledLine = getExtrapoledLine(*linea_bx[-2:])
        idLongLinesArray.append(x)
        longLinesArray.append(extrapoledLine)

    dataFrameLongLines = pd.DataFrame({'id': idLongLinesArray})
    longLinesGeoDataFrame = gpd.GeoDataFrame(dataFrameLongLines,
                                             crs=crsEpsgId,
                                             geometry=longLinesArray)
    crutils.printLogMsg(crglobals.DONE_MSG + 'Generated long lines !')

    dataFrameLineCuttedByBox = (longLinesGeoDataFrame.intersection(
        boxGeoDataFrame.geometry.iloc[0]))
    geoDataFrameLinesCuttedByBox = gpd.GeoDataFrame(
        crs=crsEpsgId, geometry=dataFrameLineCuttedByBox)
    crutils.printLogMsg(crglobals.DONE_MSG + 'Cut long lines by bounds !')

    #############################################
    ### TEST #change 06-06-2018
    #Get the convex hull lines
    convexHullFromMask = vectorMask.convex_hull.iloc[0]
    x, y = convexHullFromMask.exterior.xy
    pointsConvexHullFromMaskArray = np.array(list(zip(x, y)))
    minBBoxRect = imboundrect.minimum_bounding_rectangle(
        pointsConvexHullFromMaskArray)
    polygonOMBB = Polygon(
        [minBBoxRect[0], minBBoxRect[1], minBBoxRect[2], minBBoxRect[3]])
    #cut lines by ombb
    #longLinesGeoDataFrame
    dataFrameLineCuttedByMask = (
        geoDataFrameLinesCuttedByBox.intersection(polygonOMBB))
    #############################################

    #change 06-06-2018
    #dataFrameLineCuttedByMask=(geoDataFrameLinesCuttedByBox.intersection(vectorMask.geometry.iloc[0]))
    geoDataFrameLineCuttedByMask = gpd.GeoDataFrame(
        crs=crsEpsgId, geometry=dataFrameLineCuttedByMask)
    crutils.printLogMsg(crglobals.DONE_MSG + 'Line clipping by mask!')

    #################################
    #if cutlinedk[0].length > 0:
    #	angle=crutils.getAzimuth( (cutlinedk[0].coords[0][0]) , (cutlinedk[0].coords[0][1]) , (cutlinedk[0].coords[1][0]) ,  (cutlinedk[0].coords[1][1]) )
    #	anglep =(angle+270)
    #	xp = (np.min(box.geometry.bounds.minx)) + np.sin(np.deg2rad(anglep)) * 10
    #	yp = (np.max(box.geometry.bounds.maxy)) + np.cos(np.deg2rad(anglep)) * 10
    #	externalPoint = Point( ( xp,yp ) )
    #################################
    #print(str(anglep))
    #print(cutlinedk[0].centroid.x)
    #print(cutlinedk[0].centroid.y)
    #print('--------------ANGULO -------------------')
    #print(angle)
    #print('--------------ANGULO PERPEN-------------------')
    #xp = (cutlinedk[0].centroid.x) + np.sin(np.deg2rad(anglep)) * 20
    #yp = (cutlinedk[0].centroid.y) + np.cos(np.deg2rad(anglep)) * 20
    #print( 'POINT( %s  %s )' % ( xp,yp))

    #####
    #TODO: Order id by spatial criteria
    #####

    #line1 = LineString([(np.min(box.geometry.bounds.minx), np.min(box.geometry.bounds.miny)),
    #               (np.max(box.geometry.bounds.maxx), np.min(box.geometry.bounds.miny))])

    crutils.printLogMsg(crglobals.DONE_MSG +
                        'Calculate distance by seed criteria : %s ' %
                        (str(seedValue)))

    projectDistance = 100

    if (seedValue == 1):
        pnt0Calc = (LineString([(np.min(boxGeoDataFrame.geometry.bounds.minx),
                                 np.max(boxGeoDataFrame.geometry.bounds.maxy)),
                                (np.max(boxGeoDataFrame.geometry.bounds.maxx),
                                 np.max(boxGeoDataFrame.geometry.bounds.maxy))
                                ])).centroid
    elif (seedValue == 2):
        pnt0Calc = (LineString([(np.min(boxGeoDataFrame.geometry.bounds.minx),
                                 np.max(boxGeoDataFrame.geometry.bounds.maxy)),
                                (np.min(boxGeoDataFrame.geometry.bounds.minx),
                                 np.min(boxGeoDataFrame.geometry.bounds.miny))
                                ])).centroid
    elif (seedValue == 3):
        if dataFrameLineCuttedByMask[0].length > 0:
            angle = crutils.getAzimuth(
                (dataFrameLineCuttedByMask[0].coords[0][0]),
                (dataFrameLineCuttedByMask[0].coords[0][1]),
                (dataFrameLineCuttedByMask[0].coords[1][0]),
                (dataFrameLineCuttedByMask[0].coords[1][1]))
            anglep = (angle + 270)
            xp = (np.min(boxGeoDataFrame.geometry.bounds.minx)) + np.sin(
                np.deg2rad(anglep)) * projectDistance
            yp = (np.max(boxGeoDataFrame.geometry.bounds.maxy)) + np.cos(
                np.deg2rad(anglep)) * projectDistance
            externalPoint = Point((xp, yp))

        pnt0Calc = externalPoint
        #Point((np.min(boxGeoDataFrame.geometry.bounds.minx), np.max(boxGeoDataFrame.geometry.bounds.maxy)))
    elif (seedValue == 4):
        if dataFrameLineCuttedByMask[0].length > 0:
            angle = crutils.getAzimuth(
                (dataFrameLineCuttedByMask[0].coords[0][0]),
                (dataFrameLineCuttedByMask[0].coords[0][1]),
                (dataFrameLineCuttedByMask[0].coords[1][0]),
                (dataFrameLineCuttedByMask[0].coords[1][1]))
            anglep = (angle + 270)
            xp = (np.max(boxGeoDataFrame.geometry.bounds.maxx)) + np.sin(
                np.deg2rad(anglep)) * projectDistance
            yp = (np.max(boxGeoDataFrame.geometry.bounds.maxy)) + np.cos(
                np.deg2rad(anglep)) * projectDistance
            externalPoint = Point((xp, yp))

        pnt0Calc = externalPoint
        #pnt0Calc = Point((np.max(boxGeoDataFrame.geometry.bounds.maxx), np.max(boxGeoDataFrame.geometry.bounds.maxy)))

    boxminxmaypoint = pnt0Calc

    crutils.printLogMsg(crglobals.DONE_MSG +
                        '%s chosen for distance calculation' %
                        (boxminxmaypoint))

    for x in range(0, len(geoDataFrameLineCuttedByMask.geometry)):
        if geoDataFrameLineCuttedByMask.geometry.geom_type[x] == 'LineString':
            if (len(list(
                    geoDataFrameLineCuttedByMask.geometry[x].coords))) == 2:
                linea_bx = LineString(
                    list(geoDataFrameLineCuttedByMask.geometry[x].coords))
                if (linea_bx.length > crglobals.MINLINEDISTANCE):
                    index.append(flagCounter)
                    flagCounter += 1
                    #newidcutedline.append(x)
                    cuttedLineArray.append(linea_bx)
                    distanceLinear.append(linea_bx.length)
                    #print('centroid')
                    #print(linea_bx.centroid)
                    distanceplin = boxminxmaypoint.distance(linea_bx.centroid)
                    newobjdistances.append(distanceplin)

    sortedDistance = np.argsort(newobjdistances).astype('int')
    idByGeo = [x for _, x in sorted(zip(sortedDistance, index))]

    #Sort Distances
    newObjDistancesSorted = np.sort(newobjdistances)
    #Removing Adjacents and lines duplicates
    newObjDistancesSorted = crutils.removeAdjacentsInArray(
        newObjDistancesSorted)

    crutils.printLogMsg(crglobals.DONE_MSG +
                        'Removed adjacents and duplicate lines !')

    #print('distances: %s ' % (newobjdistances) )
    #print('---------->distances kk: %s ' % (newObjDistancesSorted) )

    ##Removing Closing Lines
    pairsdistances = zip([0] + newObjDistancesSorted, newObjDistancesSorted)
    distancesFiltered = [
        pair[1] for pair in pairsdistances
        if abs(pair[0] - pair[1]) >= crglobals.MINCROPROWDISTANCE
    ]
    #distancesFiltered = [pair[1] for pair in pairsdistances if abs(pair[0]-pair[1]) >= crglobals.MINCROPROWDISTANCE and abs(pair[0]-pair[1]) <= crglobals.MAXCROPROWDISTANCE ]

    #remove
    #add 3-9-2018
    #pairsdistances2 = zip([0]+distancesFiltered, distancesFiltered)
    #distancesFiltered = [pair2[1] for pair2 in pairsdistances2 if abs(pair2[0]-pair2[1]) <=  crglobals.MAXCROPROWDISTANCE ]
    #distancesFiltered.append(newObjDistancesSorted[len(newObjDistancesSorted)])

    crutils.printLogMsg(crglobals.DONE_MSG +
                        'Removed closing lines by proximity MIN : %s units ' %
                        (str(crglobals.MINCROPROWDISTANCE)))
    #crutils.printLogMsg(crglobals.DONE_MSG+'Removed closing lines by proximity MAX : %s units ' % ( str(crglobals.MAXCROPROWDISTANCE)) )

    #print('new x: %s ' % (distancesFiltered) )
    getIndexes = lambda x, xs: [
        i for (y, i) in zip(xs, range(len(xs))) if x == y
    ]

    #look for
    k = []
    flagCounter3 = 0
    for x in distancesFiltered:
        #print(distancesFiltered[i])
        #print(getIndexes(distancesFiltered[i],newobjdistances))
        k.append(
            getIndexes(distancesFiltered[flagCounter3], newobjdistances)[0])
        flagCounter3 = flagCounter3 + 1

    #Reindex lines filtered
    index2 = []
    flagCounter2 = 0
    m = []
    j = 0
    for x in k:
        m.append(cuttedLineArray[k[j]])
        index2.append(flagCounter2)
        flagCounter2 += 1
        j = j + 1

    sortdistance2 = np.argsort(distancesFiltered).astype('int')
    idByGeo2 = [x for _, x in sorted(zip(sortdistance2, index2))]

    crutils.printLogMsg(crglobals.DONE_MSG + 'Re-indexing candidate lines !')

    #Fix distances substracting projectDistance
    arrayDistances = np.array(distancesFiltered)
    fixdist = arrayDistances - projectDistance
    crutils.printLogMsg(crglobals.DONE_MSG + 'Distances fixed !')

    dataFrameFixedLines = pd.DataFrame({
        'id': k,
        'col': str(col),
        'row': str(row),
        'colrow': str(col) + '_' + str(row)
    })
    geoDataFrameFixedLines = gpd.GeoDataFrame(dataFrameFixedLines,
                                              crs=crsEpsgId,
                                              geometry=m)
    geoDataFrameFixedLines.dropna()

    extfile = os.path.join(
        dirNameVectorObjResults, linesExtendedFileName
    )  #dirNameVectorObjResults+'/'+linesExtendedFileName

    if (len(geoDataFrameFixedLines.values) > 0):
        #ddkfhmm.to_file(driver = 'ESRI Shapefile', filename=str(extfile))
        crutils.printLogMsg(crglobals.DONE_MSG +
                            'Writing file line extended and clipped: %s ' %
                            (extfile))
        geoDataFrameFixedLines.to_file(driver='ESRI Shapefile',
                                       filename=str(extfile))
    else:
        crutils.printLogMsg(crglobals.FAIL_MSG +
                            'Invalid geometry skip file writing: %s ' %
                            (extfile))

    return 1
def extendLinesGeom(col, row, epsgValue, dirNameVectorResults,
                    dirNameVectorObjResults, boundsVectorFile, linesVectorFile,
                    maskVectorFile, seedValue):
    """
	extendLinesGeom.

	:param col: (int) current column.
	:param row: (int) current row.
	:param dirNameVectorResults: (String) vector dir path.
	:param boundsVectorFile: (String) bounds file.
	:param linesVectorFile: (String) lines file.
	:param maskVectorFile: (String) mask file.
	:returns none: (None) nothing.
	"""

    linesExtendedFileName = crglobals.PICNAME + "-" + crglobals.COLPREFIX + str(
        col) + "-" + crglobals.ROWPREFIX + str(
            row) + "_" + crglobals.VECTORLINES + "_ext.shp"

    #os.path.join(
    if (os.path.exists(os.path.join(
            dirNameVectorResults, boundsVectorFile))) and (os.path.exists(
                os.path.join(dirNameVectorObjResults, linesVectorFile))):
        crutils.printLogMsg(
            crglobals.CHECK_MSG + 'Exists: %s' %
            (os.path.join(dirNameVectorResults, boundsVectorFile)))
        crutils.printLogMsg(
            crglobals.CHECK_MSG + 'Exists: %s' %
            (os.path.join(dirNameVectorObjResults, linesVectorFile)))
        boxGeoDataFrame = gpd.GeoDataFrame.from_file(
            os.path.join(
                dirNameVectorResults,
                boundsVectorFile))  #dirNameVectorResults+"/"+boundsVectorFile)
        try:
            linesGeoDataFrame = gpd.GeoDataFrame.from_file(
                os.path.join(dirNameVectorObjResults, linesVectorFile)
            )  #dirNameVectorObjResults+"/"+linesVectorFile)
            maskGeoDataFrame = gpd.GeoDataFrame.from_file(maskVectorFile)
            extendProcessing(boxGeoDataFrame, linesGeoDataFrame, epsgValue,
                             dirNameVectorObjResults, linesExtendedFileName,
                             maskGeoDataFrame, col, row, seedValue)
        except KeyError as exception:
            crutils.printLogMsg('Bounds file: %s' % (boundsVectorFile))
            crutils.printLogMsg('Lines file: %s' % (linesVectorFile))
            crutils.printLogMsg(crglobals.FAIL_MSG + 'Geometry not found')
    else:
        crutils.printLogMsg(
            crglobals.FAIL_MSG + 'Lines or bounds file does not exist %s' %
            (os.path.join(dirNameVectorObjResults, linesVectorFile)))

    return 1
示例#9
0
def main():
    "croprows image processing module"
    crutils.printLogMsg('croprows_image_processing [ module loaded ]')
示例#10
0
def buildContours(inputRasterImage, seed, tolerance):
    """
	buildContours.

	:param inputRasterImage: (Image) image.
	:param seed: (int) seed.
	:param tolerance: (double) tolerance.
	:returns imgContours: (Array) imgContours.
	:returns contoursAll: (Array) contoursAll.
	:returns contoursFiltred: (Array) contoursFiltred.
	:returns angleFitMinAreaRect: (double) angleFitMinAreaRect.
	:returns meanAngleFitMinAreaRect: (double) meanAngleFitMinAreaRect.
	:returns angleFitElipseContours: (double) angleFitElipseContours.
	:returns meanAngleFitElipseContours: (double) meanAngleFitElipseContours.
    """

    ##################################################
    ##   Seed Cases
    ##
    ##   __  case 1
    ##
    ##   |   case 2
    ##
    ##   /   case 3
    ##
    ##   \   case 4
    ##
    ##   O   case -1 auto search
    ##
    ##################################################
    ## Tolerance +/- in degrees
    ##################################################

    #contoursFiltred = []
    angleFitMinAreaRect = []
    angleFitElipseContours = []
    #meanAngleFitMinAreaRect = []
    #meanAngleFitElipseContours = []
    #angleFitElipseContours = []
    #imgEdges = autoCannyEdgeDetection(inputRasterImage) #Calculate edge using Canny operator
    #autocanny_canny = imgEdges.copy()
    imgEdges = inputRasterImage
    imgContours, contoursAll, hierarchy = cv2.findContours(
        inputRasterImage, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    ######
    ## preProcessingContours
    ######
    contoursAll = crutils.preProcessingContours(contoursAll)
    ######
    ## preProcessingFilteredContours
    ######
    contoursFiltred = crutils.preProcessingFilteredContours(contoursAll)

    flagCounterContour = 0

    crutils.printLogMsg(crglobals.SEPARATOR_MSG)
    crutils.printLogMsg(crglobals.OK_MSG + 'Contour Count : %s' %
                        (len(contoursFiltred)))

    for cc in contoursFiltred:
        minAreaRecContours = cv2.minAreaRect(cc)
        boxPointsContours = cv2.boxPoints(minAreaRecContours)
        angleContours = cv2.minAreaRect(boxPointsContours)[-1]
        angleFitMinAreaRect.append(angleContours)
        (x, y), (MA, ma), angleElipse = cv2.fitEllipse(cc)
        angleFitElipseContours.append(angleElipse)
        crutils.printLogMsg('Contour %s  - Max Angle: %s' %
                            ((flagCounterContour + 1), round(angleElipse, 1)))
        flagCounterContour += 1

    x = 1
    seedCases = {
        -1: lambda x: crglobals.SEEDCASES[0],
        1: lambda x: crglobals.SEEDCASES[1],
        2: lambda x: crglobals.SEEDCASES[2],
        3: lambda x: crglobals.SEEDCASES[3],
        4: lambda x: crglobals.SEEDCASES[4]
    }[seed](x)

    low = seedCases[0] - tolerance
    high = seedCases[1] + tolerance
    angleFitElipseContours = list(
        filter(lambda x: x >= low, angleFitElipseContours))
    angleFitElipseContours = list(
        filter(lambda x: x <= high, angleFitElipseContours))

    sdAngle = (np.nanstd(angleFitElipseContours))
    crutils.printLogMsg('Contours Angle SD: %s' % round(sdAngle, 1))
    maxAngle = (np.nanmax(angleFitElipseContours))
    crutils.printLogMsg('Contours Angle MAX: %s' % round(maxAngle, 1))
    minAngle = (np.nanmin(angleFitElipseContours))
    crutils.printLogMsg('Contours Angle MIN: %s' % round(minAngle, 1))
    avgAngle = (np.nanmean(angleFitElipseContours))
    crutils.printLogMsg('Contours Angle AVG: %s' % round(avgAngle, 1))

    crutils.printLogMsg(crglobals.SEPARATOR_MSG)

    if ((len(angleFitElipseContours) > int(crglobals.CONTOURAVGMAX / 2) + 2)
            and (sdAngle <= crglobals.MAXANGLEDESV)):
        #replaced mean to nanmean
        try:
            meanAngleFitMinAreaRect = (np.nanmean(angleFitMinAreaRect))
            meanAngleFitElipseContours = (np.nanmean(angleFitElipseContours))
        except RuntimeWarning:
            meanAngleFitMinAreaRect = np.NaN
            meanAngleFitElipseContours = np.NaN
    else:
        meanAngleFitMinAreaRect = np.NaN
        meanAngleFitElipseContours = np.NaN

    outputRasterImage = imgEdges

    return outputRasterImage, imgContours, contoursAll, contoursFiltred, angleFitMinAreaRect, meanAngleFitMinAreaRect, angleFitElipseContours, meanAngleFitElipseContours