|
@@ -5,10 +5,12 @@ Functions to quickly extract reduced information from image
|
|
|
from PIL import Image
|
|
|
import random
|
|
|
|
|
|
-from skimage import color
|
|
|
+import cv2
|
|
|
+from skimage import transform, color
|
|
|
import numpy as np
|
|
|
+
|
|
|
import ipfml.metrics as metrics
|
|
|
-import cv2
|
|
|
+from ipfml import exceptions
|
|
|
|
|
|
from scipy import signal
|
|
|
|
|
@@ -106,19 +108,121 @@ def get_LAB_L_SVD_V(image):
|
|
|
return metrics.get_SVD_V(L)
|
|
|
|
|
|
|
|
|
+def rgb_to_mscn(image):
|
|
|
+ """Convert RGB Image into Mean Subtracted Contrast Normalized (MSCN)
|
|
|
+
|
|
|
+ Args:
|
|
|
+ image: 3D RGB image Numpy array or PIL RGB image
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ 2D Numpy array with MSCN information
|
|
|
+
|
|
|
+ Example:
|
|
|
+
|
|
|
+ >>> from PIL import Image
|
|
|
+ >>> from ipfml import processing
|
|
|
+ >>> img = Image.open('./images/test_img.png')
|
|
|
+ >>> img_mscn = processing.rgb_to_mscn(img)
|
|
|
+ >>> img_mscn.shape
|
|
|
+ (200, 200)
|
|
|
+ """
|
|
|
+
|
|
|
+ # check if PIL image or not
|
|
|
+ img_arr = np.array(image)
|
|
|
+
|
|
|
+ # convert rgb image to gray
|
|
|
+ im = np.array(color.rgb2gray(img_arr) * 255, 'uint8')
|
|
|
+
|
|
|
+ return metrics.gray_to_mscn(im)
|
|
|
+
|
|
|
+
|
|
|
+def rgb_to_grey_low_bits(image, nb_bits=4):
|
|
|
+ """Convert RGB Image into grey image using only 4 low bits values
|
|
|
+
|
|
|
+ Args:
|
|
|
+ image: 3D RGB image Numpy array or PIL RGB image
|
|
|
+ nb_bits: optional parameter which indicates the number of bits to keep (default 4)
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ 2D Numpy array with low bits information kept
|
|
|
+
|
|
|
+ Example:
|
|
|
+
|
|
|
+ >>> from PIL import Image
|
|
|
+ >>> from ipfml import processing
|
|
|
+ >>> img = Image.open('./images/test_img.png')
|
|
|
+ >>> low_bits_grey_img = processing.rgb_to_grey_low_bits(img, 5)
|
|
|
+ >>> low_bits_grey_img.shape
|
|
|
+ (200, 200)
|
|
|
+ """
|
|
|
+
|
|
|
+ img_arr = np.array(image)
|
|
|
+ grey_block = np.array(color.rgb2gray(img_arr) * 255, 'uint8')
|
|
|
+
|
|
|
+ return metrics.get_low_bits_img(grey_block, nb_bits)
|
|
|
+
|
|
|
+
|
|
|
+def rgb_to_LAB_L_low_bits(image, nb_bits=4):
|
|
|
+ """Convert RGB Image into Lab L channel image using only 4 low bits values
|
|
|
+
|
|
|
+ Args:
|
|
|
+ image: 3D RGB image Numpy array or PIL RGB image
|
|
|
+ nb_bits: optional parameter which indicates the number of bits to keep (default 4)
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ 2D Numpy array with low bits information kept
|
|
|
+
|
|
|
+ Example:
|
|
|
+
|
|
|
+ >>> from PIL import Image
|
|
|
+ >>> from ipfml import processing
|
|
|
+ >>> img = Image.open('./images/test_img.png')
|
|
|
+ >>> low_bits_Lab_l_img = processing.rgb_to_LAB_L_low_bits(img, 5)
|
|
|
+ >>> low_bits_Lab_l_img.shape
|
|
|
+ (200, 200)
|
|
|
+ """
|
|
|
+
|
|
|
+ L_block = np.asarray(metrics.get_LAB_L(image), 'uint8')
|
|
|
+
|
|
|
+ return metrics.get_low_bits_img(L_block, nb_bits)
|
|
|
+
|
|
|
+
|
|
|
+def rgb_to_LAB_L_bits(image, interval):
|
|
|
+ """Returns only bits from LAB L canal specified into the interval
|
|
|
+
|
|
|
+ Args:
|
|
|
+ image: image to convert using this interval of bits value to keep
|
|
|
+ interval: (begin, end) of bits values
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ 2D Numpy array with reduced values
|
|
|
+
|
|
|
+ >>> from PIL import Image
|
|
|
+ >>> from ipfml import processing
|
|
|
+ >>> img = Image.open('./images/test_img.png')
|
|
|
+ >>> bits_Lab_l_img = processing.rgb_to_LAB_L_bits(img, (2, 6))
|
|
|
+ >>> bits_Lab_l_img.shape
|
|
|
+ (200, 200)
|
|
|
+ """
|
|
|
+
|
|
|
+ L_block = np.asarray(metrics.get_LAB_L(image), 'uint8')
|
|
|
+
|
|
|
+ return metrics.get_bits_img(L_block, interval)
|
|
|
+
|
|
|
+
|
|
|
def divide_in_blocks(image, block_size, pil=True):
|
|
|
'''Divide image into equal size blocks
|
|
|
|
|
|
Args:
|
|
|
image: PIL Image or Numpy array
|
|
|
block: tuple (width, height) representing the size of each dimension of the block
|
|
|
- pil: block type returned (default True)
|
|
|
+ pil: block type returned as PIL Image (default True)
|
|
|
|
|
|
Returns:
|
|
|
list containing all 2D Numpy blocks (in RGB or not)
|
|
|
|
|
|
Raises:
|
|
|
- ValueError: If `image_width` or `image_heigt` are not compatible to produce correct block sizes
|
|
|
+ ValueError: If `image_width` or `image_height` are not compatible to produce correct block sizes
|
|
|
|
|
|
Example:
|
|
|
|
|
@@ -189,103 +293,120 @@ def divide_in_blocks(image, block_size, pil=True):
|
|
|
return blocks
|
|
|
|
|
|
|
|
|
-def rgb_to_mscn(image):
|
|
|
- """Convert RGB Image into Mean Subtracted Contrast Normalized (MSCN)
|
|
|
+def fusion_images(images, pil=True):
|
|
|
+ '''Fusion array of images into single image
|
|
|
|
|
|
Args:
|
|
|
- image: 3D RGB image Numpy array or PIL RGB image
|
|
|
+ images: array of images (PIL Image or Numpy array)
|
|
|
+ pil: block type returned as PIL Image (default True)
|
|
|
|
|
|
Returns:
|
|
|
- 2D Numpy array with MSCN information
|
|
|
+ merged image from array of images
|
|
|
+
|
|
|
+ Raises:
|
|
|
+ ValueError: if `images` is not an array or is empty
|
|
|
+ NumpyShapeComparisonException: if `images` array contains images with different shapes
|
|
|
|
|
|
Example:
|
|
|
|
|
|
- >>> from PIL import Image
|
|
|
+ >>> import numpy as np
|
|
|
>>> from ipfml import processing
|
|
|
- >>> img = Image.open('./images/test_img.png')
|
|
|
- >>> img_mscn = processing.rgb_to_mscn(img)
|
|
|
- >>> img_mscn.shape
|
|
|
- (200, 200)
|
|
|
- """
|
|
|
+ >>> image_values_1 = np.random.randint(255, size=(800, 800, 3))
|
|
|
+ >>> image_values_2 = np.random.randint(255, size=(800, 800, 3))
|
|
|
+ >>> merged_image = processing.fusion_images([image_values_1, image_values_2], pil=False)
|
|
|
+ >>> merged_image.shape
|
|
|
+ (800, 800, 3)
|
|
|
+ '''
|
|
|
|
|
|
- # check if PIL image or not
|
|
|
- img_arr = np.array(image)
|
|
|
+ mode = 'RGB'
|
|
|
+ dim = 1
|
|
|
|
|
|
- # convert rgb image to gray
|
|
|
- im = np.array(color.rgb2gray(img_arr) * 255, 'uint8')
|
|
|
+ if len(images) == 0:
|
|
|
+ raise ValueError('Empty array of images provided...')
|
|
|
|
|
|
- return metrics.gray_to_mscn(im)
|
|
|
+ # convert image in numpy array (perhaps not necessary)
|
|
|
+ images = [np.asarray(img) for img in images]
|
|
|
+ image_array = images[0]
|
|
|
|
|
|
+ if image_array.ndim != 3:
|
|
|
+ mode = 'L'
|
|
|
+ width, height = image_array.shape
|
|
|
+ else:
|
|
|
+ width, height, dim = image_array.shape
|
|
|
|
|
|
-def rgb_to_grey_low_bits(image, nb_bits=4):
|
|
|
- """Convert RGB Image into grey image using only 4 low bits values
|
|
|
+ # raise exception if all images do not have same shape
|
|
|
+ if not np.array([image_array.shape == a.shape for a in images]).all():
|
|
|
+ raise NumpyShapeComparisonException()
|
|
|
|
|
|
- Args:
|
|
|
- image: 3D RGB image Numpy array or PIL RGB image
|
|
|
- nb_bits: optional parameter which indicates the number of bits to keep (default 4)
|
|
|
+ if dim == 1:
|
|
|
+ image_mean = np.empty([width, height])
|
|
|
+ else:
|
|
|
+ image_mean = np.empty([width, height, dim])
|
|
|
|
|
|
- Returns:
|
|
|
- 2D Numpy array with low bits information kept
|
|
|
+ nb_images = len(images)
|
|
|
|
|
|
- Example:
|
|
|
+ # construction of mean image from rotation
|
|
|
+ for i in range(width):
|
|
|
+ for j in range(height):
|
|
|
|
|
|
- >>> from PIL import Image
|
|
|
- >>> from ipfml import processing
|
|
|
- >>> img = Image.open('./images/test_img.png')
|
|
|
- >>> low_bits_grey_img = processing.rgb_to_grey_low_bits(img, 5)
|
|
|
- >>> low_bits_grey_img.shape
|
|
|
- (200, 200)
|
|
|
- """
|
|
|
+ if dim == 1:
|
|
|
+ grey_value = 0
|
|
|
|
|
|
- img_arr = np.array(image)
|
|
|
- grey_block = np.array(color.rgb2gray(img_arr) * 255, 'uint8')
|
|
|
+ # for each image we merge pixel values
|
|
|
+ for img in images:
|
|
|
+ grey_value += img[i][j]
|
|
|
|
|
|
- return metrics.get_low_bits_img(grey_block, nb_bits)
|
|
|
+ image_mean[i][j] = grey_value / nb_images
|
|
|
|
|
|
+ else:
|
|
|
+ for k in range(dim):
|
|
|
+ canal_value = 0
|
|
|
|
|
|
-def rgb_to_LAB_L_low_bits(image, nb_bits=4):
|
|
|
- """Convert RGB Image into Lab L channel image using only 4 low bits values
|
|
|
-
|
|
|
- Args:
|
|
|
- image: 3D RGB image Numpy array or PIL RGB image
|
|
|
- nb_bits: optional parameter which indicates the number of bits to keep (default 4)
|
|
|
-
|
|
|
- Returns:
|
|
|
- 2D Numpy array with low bits information kept
|
|
|
-
|
|
|
- Example:
|
|
|
+ # for each image we merge pixel values
|
|
|
+ for img in images:
|
|
|
+ canal_value += img[i][j][k]
|
|
|
|
|
|
- >>> from PIL import Image
|
|
|
- >>> from ipfml import processing
|
|
|
- >>> img = Image.open('./images/test_img.png')
|
|
|
- >>> low_bits_Lab_l_img = processing.rgb_to_LAB_L_low_bits(img, 5)
|
|
|
- >>> low_bits_Lab_l_img.shape
|
|
|
- (200, 200)
|
|
|
- """
|
|
|
+ image_mean[i][j][k] = canal_value / nb_images
|
|
|
|
|
|
- L_block = np.asarray(metrics.get_LAB_L(image), 'uint8')
|
|
|
+ image_mean = np.array(image_mean, 'uint8')
|
|
|
|
|
|
- return metrics.get_low_bits_img(L_block, nb_bits)
|
|
|
+ if pil:
|
|
|
+ return Image.fromarray(image_mean, mode)
|
|
|
+ else:
|
|
|
+ return image_mean
|
|
|
|
|
|
|
|
|
-def rgb_to_LAB_L_bits(image, interval):
|
|
|
- """Returns only bits from LAB L canal specified into the interval
|
|
|
+def rotate_image(image, angle=90, pil=True):
|
|
|
+ '''Rotate image using specific angle
|
|
|
|
|
|
Args:
|
|
|
- image: image to convert using this interval of bits value to keep
|
|
|
- interval: (begin, end) of bits values
|
|
|
+ image: PIL Image or Numpy array
|
|
|
+ angle: Angle value of the rotation
|
|
|
+ pil: block type returned as PIL Image (default True)
|
|
|
|
|
|
Returns:
|
|
|
- 2D Numpy array with reduced values
|
|
|
+ Image with rotation applied
|
|
|
|
|
|
- >>> from PIL import Image
|
|
|
+ Example:
|
|
|
+
|
|
|
+ >>> import numpy as np
|
|
|
>>> from ipfml import processing
|
|
|
- >>> img = Image.open('./images/test_img.png')
|
|
|
- >>> bits_Lab_l_img = processing.rgb_to_LAB_L_bits(img, (2, 6))
|
|
|
- >>> bits_Lab_l_img.shape
|
|
|
- (200, 200)
|
|
|
- """
|
|
|
+ >>> image_values = np.random.randint(255, size=(800, 800, 3))
|
|
|
+ >>> rotated_image = processing.rotate_image(image_values, 90, pil=False)
|
|
|
+ >>> rotated_image.shape
|
|
|
+ (800, 800, 3)
|
|
|
+ '''
|
|
|
|
|
|
- L_block = np.asarray(metrics.get_LAB_L(image), 'uint8')
|
|
|
+ mode = 'RGB'
|
|
|
+ image_array = np.asarray(image)
|
|
|
+
|
|
|
+ if image_array.ndim != 3:
|
|
|
+ mode = 'L'
|
|
|
+
|
|
|
+ rotated_image = np.array(transform.rotate(image_array, angle)*255, 'uint8')
|
|
|
+
|
|
|
+ if pil:
|
|
|
+ return Image.fromarray(rotated_image, mode)
|
|
|
+ else:
|
|
|
+ return rotated_image
|
|
|
|
|
|
- return metrics.get_bits_img(L_block, interval)
|