"vscode:/vscode.git/clone" did not exist on "d1c098b038b6304945c57a31b1893202d60cba88"
Unverified Commit bd9c6c4e authored by André Araujo's avatar André Araujo Committed by GitHub
Browse files

Move DELF resizing code into utils.py, which is more appropriate than extractor.py. (#9108)

* Merged commit includes the following changes:
326723075  by Andre Araujo:

    Move image resize utility into utils.py.

--

PiperOrigin-RevId: 326723075

* Adding back matched_images_demo.png
parent e8ea6b7d
......@@ -19,81 +19,18 @@ from __future__ import division
from __future__ import print_function
import numpy as np
from PIL import Image
import tensorflow as tf
from delf import datum_io
from delf import feature_extractor
from delf import utils
# Minimum dimensions below which DELF features are not extracted (empty
# Minimum dimensions below which features are not extracted (empty
# features are returned). This applies after any resizing is performed.
_MIN_HEIGHT = 10
_MIN_WIDTH = 10
def ResizeImage(image, config, resize_factor=1.0):
"""Resizes image according to config.
Args:
image: Uint8 array with shape (height, width, 3).
config: DelfConfig proto containing the model configuration.
resize_factor: Optional float resize factor for the input image. If given,
the maximum and minimum allowed image sizes in `config` are scaled by this
factor. Must be non-negative.
Returns:
resized_image: Uint8 array with resized image.
scale_factors: 2D float array, with factors used for resizing along height
and width (If upscaling, larger than 1; if downscaling, smaller than 1).
Raises:
ValueError: If `image` has incorrect number of dimensions/channels.
"""
if resize_factor < 0.0:
raise ValueError('negative resize_factor is not allowed: %f' %
resize_factor)
if image.ndim != 3:
raise ValueError('image has incorrect number of dimensions: %d' %
image.ndims)
height, width, channels = image.shape
# Take into account resize factor.
max_image_size = resize_factor * config.max_image_size
min_image_size = resize_factor * config.min_image_size
if channels != 3:
raise ValueError('image has incorrect number of channels: %d' % channels)
largest_side = max(width, height)
if max_image_size >= 0 and largest_side > max_image_size:
scale_factor = max_image_size / largest_side
elif min_image_size >= 0 and largest_side < min_image_size:
scale_factor = min_image_size / largest_side
elif config.use_square_images and (height != width):
scale_factor = 1.0
else:
# No resizing needed, early return.
return image, np.ones(2, dtype=float)
# Note that new_shape is in (width, height) format (PIL convention), while
# scale_factors are in (height, width) convention (NumPy convention).
if config.use_square_images:
new_shape = (int(round(largest_side * scale_factor)),
int(round(largest_side * scale_factor)))
else:
new_shape = (int(round(width * scale_factor)),
int(round(height * scale_factor)))
scale_factors = np.array([new_shape[1] / height, new_shape[0] / width],
dtype=float)
pil_image = Image.fromarray(image)
resized_image = np.array(pil_image.resize(new_shape, resample=Image.BILINEAR))
return resized_image, scale_factors
def MakeExtractor(config):
"""Creates a function to extract global and/or local features from an image.
......@@ -206,7 +143,7 @@ def MakeExtractor(config):
features (key 'local_features' mapping to a dict with keys 'locations',
'descriptors', 'scales', 'attention').
"""
resized_image, scale_factors = ResizeImage(
resized_image, scale_factors = utils.ResizeImage(
image, config, resize_factor=resize_factor)
# If the image is too small, returns empty features.
......
......@@ -18,6 +18,7 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
from PIL import Image
from PIL import ImageFile
import tensorflow as tf
......@@ -39,3 +40,65 @@ def RgbLoader(path):
img = Image.open(f)
return img.convert('RGB')
def ResizeImage(image, config, resize_factor=1.0):
"""Resizes image according to config.
Args:
image: Uint8 array with shape (height, width, 3).
config: DelfConfig proto containing the model configuration.
resize_factor: Optional float resize factor for the input image. If given,
the maximum and minimum allowed image sizes in `config` are scaled by this
factor. Must be non-negative.
Returns:
resized_image: Uint8 array with resized image.
scale_factors: 2D float array, with factors used for resizing along height
and width (If upscaling, larger than 1; if downscaling, smaller than 1).
Raises:
ValueError: If `image` has incorrect number of dimensions/channels.
"""
if resize_factor < 0.0:
raise ValueError('negative resize_factor is not allowed: %f' %
resize_factor)
if image.ndim != 3:
raise ValueError('image has incorrect number of dimensions: %d' %
image.ndims)
height, width, channels = image.shape
# Take into account resize factor.
max_image_size = resize_factor * config.max_image_size
min_image_size = resize_factor * config.min_image_size
if channels != 3:
raise ValueError('image has incorrect number of channels: %d' % channels)
largest_side = max(width, height)
if max_image_size >= 0 and largest_side > max_image_size:
scale_factor = max_image_size / largest_side
elif min_image_size >= 0 and largest_side < min_image_size:
scale_factor = min_image_size / largest_side
elif config.use_square_images and (height != width):
scale_factor = 1.0
else:
# No resizing needed, early return.
return image, np.ones(2, dtype=float)
# Note that new_shape is in (width, height) format (PIL convention), while
# scale_factors are in (height, width) convention (NumPy convention).
if config.use_square_images:
new_shape = (int(round(largest_side * scale_factor)),
int(round(largest_side * scale_factor)))
else:
new_shape = (int(round(width * scale_factor)),
int(round(height * scale_factor)))
scale_factors = np.array([new_shape[1] / height, new_shape[0] / width],
dtype=float)
pil_image = Image.fromarray(image)
resized_image = np.array(pil_image.resize(new_shape, resample=Image.BILINEAR))
return resized_image, scale_factors
# Copyright 2019 The TensorFlow Authors All Rights Reserved.
# Copyright 2020 The TensorFlow Authors All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
......@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for DELF feature extractor."""
"""Tests for helper utilities."""
from __future__ import absolute_import
from __future__ import division
......@@ -23,10 +23,10 @@ import numpy as np
import tensorflow as tf
from delf import delf_config_pb2
from delf import extractor
from delf import utils
class ExtractorTest(tf.test.TestCase, parameterized.TestCase):
class UtilsTest(tf.test.TestCase, parameterized.TestCase):
@parameterized.named_parameters(
('Max-1Min-1', -1, -1, 1.0, False, [4, 2, 3], [1.0, 1.0]),
......@@ -70,8 +70,8 @@ class ExtractorTest(tf.test.TestCase, parameterized.TestCase):
min_image_size=min_image_size,
use_square_images=square_output)
resized_image, scale_factors = extractor.ResizeImage(
image, config, resize_factor)
resized_image, scale_factors = utils.ResizeImage(image, config,
resize_factor)
self.assertAllEqual(resized_image.shape, expected_shape)
self.assertAllClose(scale_factors, expected_scale_factors)
......@@ -93,8 +93,8 @@ class ExtractorTest(tf.test.TestCase, parameterized.TestCase):
min_image_size=min_image_size,
use_square_images=square_output)
resized_image, scale_factors = extractor.ResizeImage(
image, config, resize_factor)
resized_image, scale_factors = utils.ResizeImage(image, config,
resize_factor)
self.assertAllEqual(resized_image.shape, expected_shape)
self.assertAllClose(scale_factors, expected_scale_factors)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment