hand
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
# Copyright 2021 The MediaPipe Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for mediapipe.python._framework_bindings.image."""
|
||||
|
||||
import gc
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
from absl.testing import absltest
|
||||
import cv2
|
||||
import numpy as np
|
||||
import PIL.Image
|
||||
|
||||
# resources dependency
|
||||
from mediapipe.python._framework_bindings import image
|
||||
from mediapipe.python._framework_bindings import image_frame
|
||||
|
||||
TEST_IMAGE_PATH = 'mediapipe/python/solutions/testdata'
|
||||
|
||||
Image = image.Image
|
||||
ImageFormat = image_frame.ImageFormat
|
||||
|
||||
|
||||
# TODO: Add unit tests specifically for memory management.
|
||||
class ImageTest(absltest.TestCase):
|
||||
|
||||
def test_create_image_from_gray_cv_mat(self):
|
||||
w, h = random.randrange(3, 100), random.randrange(3, 100)
|
||||
mat = cv2.cvtColor(
|
||||
np.random.randint(2**8 - 1, size=(h, w, 3), dtype=np.uint8),
|
||||
cv2.COLOR_RGB2GRAY)
|
||||
mat[2, 2] = 42
|
||||
gray8_image = Image(image_format=ImageFormat.GRAY8, data=mat)
|
||||
self.assertTrue(np.array_equal(mat, gray8_image.numpy_view()))
|
||||
with self.assertRaisesRegex(IndexError, 'index dimension mismatch'):
|
||||
print(gray8_image[w, h, 1])
|
||||
with self.assertRaisesRegex(IndexError, 'out of bounds'):
|
||||
print(gray8_image[w, h])
|
||||
self.assertEqual(42, gray8_image[2, 2])
|
||||
|
||||
def test_create_image_from_rgb_cv_mat(self):
|
||||
w, h, channels = random.randrange(3, 100), random.randrange(3, 100), 3
|
||||
mat = cv2.cvtColor(
|
||||
np.random.randint(2**8 - 1, size=(h, w, channels), dtype=np.uint8),
|
||||
cv2.COLOR_RGB2BGR)
|
||||
mat[2, 2, 1] = 42
|
||||
rgb_image = Image(image_format=ImageFormat.SRGB, data=mat)
|
||||
self.assertTrue(np.array_equal(mat, rgb_image.numpy_view()))
|
||||
with self.assertRaisesRegex(IndexError, 'out of bounds'):
|
||||
print(rgb_image[w, h, channels])
|
||||
self.assertEqual(42, rgb_image[2, 2, 1])
|
||||
|
||||
def test_create_image_from_rgb48_cv_mat(self):
|
||||
w, h, channels = random.randrange(3, 100), random.randrange(3, 100), 3
|
||||
mat = cv2.cvtColor(
|
||||
np.random.randint(2**16 - 1, size=(h, w, channels), dtype=np.uint16),
|
||||
cv2.COLOR_RGB2BGR)
|
||||
mat[2, 2, 1] = 42
|
||||
rgb48_image = Image(image_format=ImageFormat.SRGB48, data=mat)
|
||||
self.assertTrue(np.array_equal(mat, rgb48_image.numpy_view()))
|
||||
with self.assertRaisesRegex(IndexError, 'out of bounds'):
|
||||
print(rgb48_image[w, h, channels])
|
||||
self.assertEqual(42, rgb48_image[2, 2, 1])
|
||||
|
||||
def test_create_image_from_gray_pil_image(self):
|
||||
w, h = random.randrange(3, 100), random.randrange(3, 100)
|
||||
img = PIL.Image.fromarray(
|
||||
np.random.randint(2**8 - 1, size=(h, w), dtype=np.uint8), 'L')
|
||||
gray8_image = Image(image_format=ImageFormat.GRAY8, data=np.asarray(img))
|
||||
self.assertTrue(np.array_equal(np.asarray(img), gray8_image.numpy_view()))
|
||||
with self.assertRaisesRegex(IndexError, 'index dimension mismatch'):
|
||||
print(gray8_image[w, h, 1])
|
||||
with self.assertRaisesRegex(IndexError, 'out of bounds'):
|
||||
print(gray8_image[w, h])
|
||||
|
||||
def test_create_image_from_rgb_pil_image(self):
|
||||
w, h, channels = random.randrange(3, 100), random.randrange(3, 100), 3
|
||||
img = PIL.Image.fromarray(
|
||||
np.random.randint(2**8 - 1, size=(h, w, channels), dtype=np.uint8),
|
||||
'RGB')
|
||||
rgb_image = Image(image_format=ImageFormat.SRGB, data=np.asarray(img))
|
||||
self.assertTrue(np.array_equal(np.asarray(img), rgb_image.numpy_view()))
|
||||
with self.assertRaisesRegex(IndexError, 'out of bounds'):
|
||||
print(rgb_image[w, h, channels])
|
||||
|
||||
def test_create_image_from_rgba64_pil_image(self):
|
||||
w, h, channels = random.randrange(3, 100), random.randrange(3, 100), 4
|
||||
img = PIL.Image.fromarray(
|
||||
np.random.randint(2**16 - 1, size=(h, w, channels), dtype=np.uint16),
|
||||
'RGBA')
|
||||
rgba_image = Image(
|
||||
image_format=ImageFormat.SRGBA64,
|
||||
data=np.asarray(img).astype(np.uint16))
|
||||
self.assertTrue(np.array_equal(np.asarray(img), rgba_image.numpy_view()))
|
||||
with self.assertRaisesRegex(IndexError, 'out of bounds'):
|
||||
print(rgba_image[1000, 1000, 1000])
|
||||
|
||||
def test_image_numby_view(self):
|
||||
w, h, channels = random.randrange(3, 100), random.randrange(3, 100), 3
|
||||
mat = cv2.cvtColor(
|
||||
np.random.randint(2**8 - 1, size=(h, w, channels), dtype=np.uint8),
|
||||
cv2.COLOR_RGB2BGR)
|
||||
rgb_image = Image(image_format=ImageFormat.SRGB, data=mat)
|
||||
output_ndarray = rgb_image.numpy_view()
|
||||
self.assertTrue(np.array_equal(mat, rgb_image.numpy_view()))
|
||||
# The output of numpy_view() is a reference to the internal data and it's
|
||||
# unwritable after creation.
|
||||
with self.assertRaisesRegex(ValueError,
|
||||
'assignment destination is read-only'):
|
||||
output_ndarray[0, 0, 0] = 0
|
||||
copied_ndarray = np.copy(output_ndarray)
|
||||
copied_ndarray[0, 0, 0] = 0
|
||||
|
||||
def test_cropped_gray8_image(self):
|
||||
w, h = random.randrange(20, 100), random.randrange(20, 100)
|
||||
channels, offset = 3, 10
|
||||
mat = cv2.cvtColor(
|
||||
np.random.randint(2**8 - 1, size=(h, w, channels), dtype=np.uint8),
|
||||
cv2.COLOR_RGB2GRAY)
|
||||
gray8_image = Image(
|
||||
image_format=ImageFormat.GRAY8,
|
||||
data=np.ascontiguousarray(mat[offset:-offset, offset:-offset]))
|
||||
self.assertTrue(
|
||||
np.array_equal(mat[offset:-offset, offset:-offset],
|
||||
gray8_image.numpy_view()))
|
||||
|
||||
def test_cropped_rgb_image(self):
|
||||
w, h = random.randrange(20, 100), random.randrange(20, 100)
|
||||
channels, offset = 3, 10
|
||||
mat = cv2.cvtColor(
|
||||
np.random.randint(2**8 - 1, size=(h, w, channels), dtype=np.uint8),
|
||||
cv2.COLOR_RGB2BGR)
|
||||
rgb_image = Image(
|
||||
image_format=ImageFormat.SRGB,
|
||||
data=np.ascontiguousarray(mat[offset:-offset, offset:-offset, :]))
|
||||
self.assertTrue(
|
||||
np.array_equal(mat[offset:-offset, offset:-offset, :],
|
||||
rgb_image.numpy_view()))
|
||||
|
||||
# For image frames that store contiguous data, the output of numpy_view()
|
||||
# points to the pixel data of the original image frame object. The life cycle
|
||||
# of the data array should tie to the image frame object.
|
||||
def test_image_numpy_view_with_contiguous_data(self):
|
||||
w, h = 640, 480
|
||||
mat = np.random.randint(2**8 - 1, size=(h, w, 3), dtype=np.uint8)
|
||||
rgb_image = Image(image_format=ImageFormat.SRGB, data=mat)
|
||||
self.assertTrue(rgb_image.is_contiguous())
|
||||
initial_ref_count = sys.getrefcount(rgb_image)
|
||||
self.assertTrue(np.array_equal(mat, rgb_image.numpy_view()))
|
||||
# Get 2 data array objects and verify that the image frame's ref count is
|
||||
# increased by 2.
|
||||
np_view = rgb_image.numpy_view()
|
||||
self.assertEqual(sys.getrefcount(rgb_image), initial_ref_count + 1)
|
||||
np_view2 = rgb_image.numpy_view()
|
||||
self.assertEqual(sys.getrefcount(rgb_image), initial_ref_count + 2)
|
||||
del np_view
|
||||
del np_view2
|
||||
gc.collect()
|
||||
# After the two data array objects getting destroyed, the current ref count
|
||||
# should euqal to the initial ref count.
|
||||
self.assertEqual(sys.getrefcount(rgb_image), initial_ref_count)
|
||||
|
||||
# For image frames that store non contiguous data, the output of numpy_view()
|
||||
# stores a copy of the pixel data of the image frame object. The life cycle of
|
||||
# the data array doesn't tie to the image frame object.
|
||||
def test_image_numpy_view_with_non_contiguous_data(self):
|
||||
w, h = 641, 481
|
||||
mat = np.random.randint(2**8 - 1, size=(h, w, 3), dtype=np.uint8)
|
||||
rgb_image = Image(image_format=ImageFormat.SRGB, data=mat)
|
||||
self.assertFalse(rgb_image.is_contiguous())
|
||||
initial_ref_count = sys.getrefcount(rgb_image)
|
||||
self.assertTrue(np.array_equal(mat, rgb_image.numpy_view()))
|
||||
np_view = rgb_image.numpy_view()
|
||||
self.assertEqual(sys.getrefcount(rgb_image), initial_ref_count)
|
||||
del np_view
|
||||
gc.collect()
|
||||
self.assertEqual(sys.getrefcount(rgb_image), initial_ref_count)
|
||||
|
||||
def test_image_create_from_cvmat(self):
|
||||
image_path = os.path.join(os.path.dirname(__file__),
|
||||
'solutions/testdata/hands.jpg')
|
||||
mat = cv2.imread(image_path).astype(np.uint8)
|
||||
mat = cv2.cvtColor(mat, cv2.COLOR_BGR2RGB)
|
||||
rgb_image = Image(image_format=ImageFormat.SRGB, data=mat)
|
||||
self.assertEqual(rgb_image.width, 720)
|
||||
self.assertEqual(rgb_image.height, 382)
|
||||
self.assertEqual(rgb_image.channels, 3)
|
||||
self.assertEqual(rgb_image.image_format, ImageFormat.SRGB)
|
||||
self.assertTrue(np.array_equal(mat, rgb_image.numpy_view()))
|
||||
|
||||
def test_image_create_from_file(self):
|
||||
image_path = os.path.join(os.path.dirname(__file__),
|
||||
'solutions/testdata/hands.jpg')
|
||||
loaded_image = Image.create_from_file(image_path)
|
||||
self.assertEqual(loaded_image.width, 720)
|
||||
self.assertEqual(loaded_image.height, 382)
|
||||
# On Mac w/ GPU support, images use 4 channels (SRGBA). Otherwise, all
|
||||
# images use 3 channels (SRGB).
|
||||
self.assertIn(loaded_image.channels, [3, 4])
|
||||
self.assertIn(
|
||||
loaded_image.image_format, [ImageFormat.SRGB, ImageFormat.SRGBA]
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
absltest.main()
|
||||
Reference in New Issue
Block a user