kopia lustrzana https://github.com/OpenDroneMap/ODM
				
				
				
			feat: add --compact-overviews config param for slim orthophoto overviews
							rodzic
							
								
									29800652c6
								
							
						
					
					
						commit
						7f3a40c45f
					
				| 
						 | 
				
			
			@ -5,7 +5,7 @@ from opendm.concurrency import get_max_memory
 | 
			
		|||
from opendm import io
 | 
			
		||||
from opendm import log
 | 
			
		||||
 | 
			
		||||
def convert_to_cogeo(src_path, blocksize=256, max_workers=1, compression="DEFLATE"):
 | 
			
		||||
def convert_to_cogeo(src_path, blocksize=256, max_workers=1, compression="DEFLATE", compact_overviews=False):
 | 
			
		||||
    """
 | 
			
		||||
    Guarantee that the .tif passed as an argument is a Cloud Optimized GeoTIFF (cogeo)
 | 
			
		||||
    The file is destructively converted into a cogeo.
 | 
			
		||||
| 
						 | 
				
			
			@ -15,39 +15,49 @@ def convert_to_cogeo(src_path, blocksize=256, max_workers=1, compression="DEFLAT
 | 
			
		|||
    """
 | 
			
		||||
 | 
			
		||||
    if not os.path.isfile(src_path):
 | 
			
		||||
        logger.warning("Cannot convert to cogeo: %s (file does not exist)" % src_path)
 | 
			
		||||
        log.ODM_WARNING("Cannot convert to cogeo: %s (file does not exist)" % src_path)
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    log.ODM_INFO("Optimizing %s as Cloud Optimized GeoTIFF" % src_path)
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    tmpfile = io.related_file_path(src_path, postfix='_cogeo')
 | 
			
		||||
    swapfile = io.related_file_path(src_path, postfix='_cogeo_swap')
 | 
			
		||||
 | 
			
		||||
    kwargs = {
 | 
			
		||||
        'threads': max_workers if max_workers else 'ALL_CPUS',
 | 
			
		||||
        'blocksize': blocksize,
 | 
			
		||||
        'max_memory': get_max_memory(),
 | 
			
		||||
        'src_path': src_path,
 | 
			
		||||
        'tmpfile': tmpfile,
 | 
			
		||||
        'compress': compression,
 | 
			
		||||
        'predictor': '2' if compression in ['LZW', 'DEFLATE'] else '1',
 | 
			
		||||
    }
 | 
			
		||||
    # Configuration params
 | 
			
		||||
    threads = max_workers if max_workers else 'ALL_CPUS'
 | 
			
		||||
    predictor = '2' if compression in ['LZW', 'DEFLATE'] else '1'
 | 
			
		||||
    max_memory = get_max_memory()
 | 
			
		||||
 | 
			
		||||
    # Build gdal_translate command
 | 
			
		||||
    cmd = [
 | 
			
		||||
        'gdal_translate',
 | 
			
		||||
        '-of', 'COG',
 | 
			
		||||
        '-co', f'NUM_THREADS={threads}',
 | 
			
		||||
        '-co', f'BLOCKSIZE={blocksize}',
 | 
			
		||||
        '-co', f'COMPRESS={compression}',
 | 
			
		||||
        '-co', f'PREDICTOR={predictor}',
 | 
			
		||||
        '-co', 'BIGTIFF=IF_SAFER',
 | 
			
		||||
        '-co', 'RESAMPLING=NEAREST',
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    if compact_overviews:
 | 
			
		||||
        cmd.extend([
 | 
			
		||||
            '-co', 'PHOTOMETRIC_OVERVIEW=YCBCR',
 | 
			
		||||
            '-co', 'INTERLEAVE_OVERVIEW=PIXEL',
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
    cmd.extend([
 | 
			
		||||
        '--config', 'GDAL_CACHEMAX', f'{max_memory}%',
 | 
			
		||||
        '--config', 'GDAL_NUM_THREADS', str(threads),
 | 
			
		||||
        src_path,
 | 
			
		||||
        tmpfile,
 | 
			
		||||
    ])
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        system.run("gdal_translate "
 | 
			
		||||
                "-of COG "
 | 
			
		||||
                "-co NUM_THREADS={threads} "
 | 
			
		||||
                "-co BLOCKSIZE={blocksize} "
 | 
			
		||||
                "-co COMPRESS={compress} "
 | 
			
		||||
                "-co PREDICTOR={predictor} "
 | 
			
		||||
                "-co BIGTIFF=IF_SAFER "
 | 
			
		||||
                "-co RESAMPLING=NEAREST "
 | 
			
		||||
                "--config GDAL_CACHEMAX {max_memory}% "
 | 
			
		||||
                "--config GDAL_NUM_THREADS {threads} "
 | 
			
		||||
                "\"{src_path}\" \"{tmpfile}\" ".format(**kwargs))
 | 
			
		||||
        system.run(' '.join(cmd))
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        log.ODM_WARNING("Cannot create Cloud Optimized GeoTIFF: %s" % str(e))
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    if os.path.isfile(tmpfile):
 | 
			
		||||
        shutil.move(src_path, swapfile) # Move to swap location
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +67,7 @@ def convert_to_cogeo(src_path, blocksize=256, max_workers=1, compression="DEFLAT
 | 
			
		|||
        except IOError as e:
 | 
			
		||||
            log.ODM_WARNING("Cannot move %s to %s: %s" % (tmpfile, src_path, str(e)))
 | 
			
		||||
            shutil.move(swapfile, src_path) # Attempt to restore
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        if os.path.isfile(swapfile):
 | 
			
		||||
            os.remove(swapfile)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -740,6 +740,12 @@ def config(argv=None, parser=None):
 | 
			
		|||
                        default=False,
 | 
			
		||||
                        help='Build orthophoto overviews for faster display in programs such as QGIS. Default: %(default)s')
 | 
			
		||||
 | 
			
		||||
    parser.add_argument('--compact-overviews',
 | 
			
		||||
                        action=StoreTrue,
 | 
			
		||||
                        nargs=0,
 | 
			
		||||
                        default=False,
 | 
			
		||||
                        help='Use addtional compression for orthophoto overviews, to improve viewing performance. Default: %(default)s')
 | 
			
		||||
 | 
			
		||||
    parser.add_argument('--cog',
 | 
			
		||||
                        action=StoreTrue,
 | 
			
		||||
                        nargs=0,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,15 +29,31 @@ def get_orthophoto_vars(args):
 | 
			
		|||
        'NUM_THREADS': args.max_concurrency
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
def build_overviews(orthophoto_file):
 | 
			
		||||
def build_overviews(orthophoto_file, compact_overviews=False):
 | 
			
		||||
    """
 | 
			
		||||
    Build overviews for an orthophoto file using gdaladdo
 | 
			
		||||
    :param orthophoto_file: path to orthophoto
 | 
			
		||||
    :param compact_overviews: whether to use compact overview settings
 | 
			
		||||
    """
 | 
			
		||||
    log.ODM_INFO("Building Overviews")
 | 
			
		||||
    kwargs = {'orthophoto': orthophoto_file}
 | 
			
		||||
    
 | 
			
		||||
    # Run gdaladdo
 | 
			
		||||
    system.run('gdaladdo -r average '
 | 
			
		||||
                '--config BIGTIFF_OVERVIEW IF_SAFER '
 | 
			
		||||
                '--config COMPRESS_OVERVIEW JPEG '
 | 
			
		||||
                '{orthophoto} 2 4 8 16'.format(**kwargs))
 | 
			
		||||
    # Build gdaladdo command
 | 
			
		||||
    cmd = [
 | 
			
		||||
        'gdaladdo',
 | 
			
		||||
        '-r', 'average',
 | 
			
		||||
        '--config', 'BIGTIFF_OVERVIEW', 'IF_SAFER',
 | 
			
		||||
        '--config', 'COMPRESS_OVERVIEW', 'JPG',
 | 
			
		||||
    ]
 | 
			
		||||
    
 | 
			
		||||
    if compact_overviews:
 | 
			
		||||
        cmd.extend([
 | 
			
		||||
            '--config', 'PHOTOMETRIC_OVERVIEW', 'YCBCR',
 | 
			
		||||
            '--config', 'INTERLEAVE_OVERVIEW', 'PIXEL',
 | 
			
		||||
        ])
 | 
			
		||||
    
 | 
			
		||||
    cmd.extend([orthophoto_file, '2', '4', '8', '16'])
 | 
			
		||||
 | 
			
		||||
    system.run(' '.join(cmd))
 | 
			
		||||
 | 
			
		||||
def generate_png(orthophoto_file, output_file=None, outsize=None):
 | 
			
		||||
    if output_file is None:
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +188,7 @@ def post_orthophoto_steps(args, bounds_file_path, orthophoto_file, orthophoto_ti
 | 
			
		|||
        Cropper.crop(bounds_file_path, orthophoto_file, get_orthophoto_vars(args), keep_original=not args.optimize_disk_space, warp_options=['-dstalpha'])
 | 
			
		||||
 | 
			
		||||
    if args.build_overviews and not args.cog:
 | 
			
		||||
        build_overviews(orthophoto_file)
 | 
			
		||||
        build_overviews(orthophoto_file, compact_overviews=args.compact_overviews)
 | 
			
		||||
 | 
			
		||||
    if args.orthophoto_png:
 | 
			
		||||
        generate_png(orthophoto_file)
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +202,7 @@ def post_orthophoto_steps(args, bounds_file_path, orthophoto_file, orthophoto_ti
 | 
			
		|||
        generate_orthophoto_tiles(orthophoto_file, orthophoto_tiles_dir, args.max_concurrency, resolution)
 | 
			
		||||
 | 
			
		||||
    if args.cog:
 | 
			
		||||
        convert_to_cogeo(orthophoto_file, max_workers=args.max_concurrency, compression=args.orthophoto_compression)
 | 
			
		||||
        convert_to_cogeo(orthophoto_file, max_workers=args.max_concurrency, compression=args.orthophoto_compression, compact_overviews=args.compact_overviews)
 | 
			
		||||
 | 
			
		||||
    generate_extent_polygon(orthophoto_file)
 | 
			
		||||
    generate_tfw(orthophoto_file)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue