Browse Source

Processing methods added

Jérôme BUISINE 2 years ago
parent
commit
88c9c8d650

BIN
docs/build/doctrees/environment.pickle


BIN
docs/build/doctrees/ipfml/ipfml.processing.doctree


+ 1 - 1
docs/build/html/.buildinfo

@@ -1,4 +1,4 @@
 # Sphinx build info version 1
 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
-config: 6da015888a7b3ff924fe46518350c0ef
+config: 2ba2dcd178d8c98ffdade52250f9b9e5
 tags: 645f666f9bcd5a90fca523b33c5a78b7

+ 2 - 2
docs/build/html/_modules/index.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Overview: module code &mdash; IPFML v0.3.0 documentation</title>
+  <title>Overview: module code &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -56,7 +56,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/_modules/ipfml/exceptions.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>ipfml.exceptions &mdash; IPFML v0.3.0 documentation</title>
+  <title>ipfml.exceptions &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -56,7 +56,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/_modules/ipfml/filters/noise.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>ipfml.filters.noise &mdash; IPFML v0.3.0 documentation</title>
+  <title>ipfml.filters.noise &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -56,7 +56,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/_modules/ipfml/iqa/fr.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>ipfml.iqa.fr &mdash; IPFML v0.3.0 documentation</title>
+  <title>ipfml.iqa.fr &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -56,7 +56,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/_modules/ipfml/metrics.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>ipfml.metrics &mdash; IPFML v0.3.0 documentation</title>
+  <title>ipfml.metrics &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -56,7 +56,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

File diff suppressed because it is too large
+ 197 - 72
docs/build/html/_modules/ipfml/processing.html


+ 2 - 2
docs/build/html/_modules/ipfml/utils.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>ipfml.utils &mdash; IPFML v0.3.0 documentation</title>
+  <title>ipfml.utils &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -56,7 +56,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 1 - 1
docs/build/html/_static/documentation_options.js

@@ -1,6 +1,6 @@
 var DOCUMENTATION_OPTIONS = {
     URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
-    VERSION: 'v0.3.0',
+    VERSION: 'v0.3.1',
     LANGUAGE: 'None',
     COLLAPSE_INDEX: false,
     FILE_SUFFIX: '.html',

+ 2 - 2
docs/build/html/contributing.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Contributing &mdash; IPFML v0.3.0 documentation</title>
+  <title>Contributing &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -57,7 +57,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/description.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Description &mdash; IPFML v0.3.0 documentation</title>
+  <title>Description &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -58,7 +58,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/examples.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Examples &mdash; IPFML v0.3.0 documentation</title>
+  <title>Examples &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -58,7 +58,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 15 - 4
docs/build/html/genindex.html

@@ -9,7 +9,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Index &mdash; IPFML v0.3.0 documentation</title>
+  <title>Index &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -57,7 +57,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           
@@ -159,6 +159,7 @@
 <div class="genindex-jumpbox">
  <a href="#C"><strong>C</strong></a>
  | <a href="#D"><strong>D</strong></a>
+ | <a href="#F"><strong>F</strong></a>
  | <a href="#G"><strong>G</strong></a>
  | <a href="#I"><strong>I</strong></a>
  | <a href="#L"><strong>L</strong></a>
@@ -187,6 +188,14 @@
   </ul></td>
 </tr></table>
 
+<h2 id="F">F</h2>
+<table style="width: 100%" class="indextable genindextable"><tr>
+  <td style="width: 33%; vertical-align: top;"><ul>
+      <li><a href="ipfml/ipfml.processing.html#ipfml.processing.fusion_images">fusion_images() (in module ipfml.processing)</a>
+</li>
+  </ul></td>
+</tr></table>
+
 <h2 id="G">G</h2>
 <table style="width: 100%" class="indextable genindextable"><tr>
   <td style="width: 33%; vertical-align: top;"><ul>
@@ -316,13 +325,15 @@
 </li>
       <li><a href="ipfml/ipfml.processing.html#ipfml.processing.rgb_to_LAB_L_bits">rgb_to_LAB_L_bits() (in module ipfml.processing)</a>
 </li>
-  </ul></td>
-  <td style="width: 33%; vertical-align: top;"><ul>
       <li><a href="ipfml/ipfml.processing.html#ipfml.processing.rgb_to_LAB_L_low_bits">rgb_to_LAB_L_low_bits() (in module ipfml.processing)</a>
 </li>
+  </ul></td>
+  <td style="width: 33%; vertical-align: top;"><ul>
       <li><a href="ipfml/ipfml.processing.html#ipfml.processing.rgb_to_mscn">rgb_to_mscn() (in module ipfml.processing)</a>
 </li>
       <li><a href="ipfml/ipfml.iqa.fr.html#ipfml.iqa.fr.rmse">rmse() (in module ipfml.iqa.fr)</a>
+</li>
+      <li><a href="ipfml/ipfml.processing.html#ipfml.processing.rotate_image">rotate_image() (in module ipfml.processing)</a>
 </li>
   </ul></td>
 </tr></table>

+ 2 - 2
docs/build/html/index.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Image Processing For Machine Learning &mdash; IPFML v0.3.0 documentation</title>
+  <title>Image Processing For Machine Learning &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -57,7 +57,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/ipfml.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Documentation &mdash; IPFML v0.3.0 documentation</title>
+  <title>Documentation &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -58,7 +58,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/ipfml/ipfml.exceptions.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>ipfml.exceptions &mdash; IPFML v0.3.0 documentation</title>
+  <title>ipfml.exceptions &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -58,7 +58,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/ipfml/ipfml.filters.noise.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>ipfml.filters.noise &mdash; IPFML v0.3.0 documentation</title>
+  <title>ipfml.filters.noise &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -58,7 +58,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/ipfml/ipfml.iqa.fr.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>ipfml.iqa.fr &mdash; IPFML v0.3.0 documentation</title>
+  <title>ipfml.iqa.fr &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -58,7 +58,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/ipfml/ipfml.metrics.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>ipfml.metrics &mdash; IPFML v0.3.0 documentation</title>
+  <title>ipfml.metrics &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -58,7 +58,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

File diff suppressed because it is too large
+ 72 - 4
docs/build/html/ipfml/ipfml.processing.html


+ 2 - 2
docs/build/html/ipfml/ipfml.utils.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>ipfml.utils &mdash; IPFML v0.3.0 documentation</title>
+  <title>ipfml.utils &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -58,7 +58,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

BIN
docs/build/html/objects.inv


+ 2 - 2
docs/build/html/py-modindex.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Python Module Index &mdash; IPFML v0.3.0 documentation</title>
+  <title>Python Module Index &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -59,7 +59,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

+ 2 - 2
docs/build/html/search.html

@@ -8,7 +8,7 @@
   
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   
-  <title>Search &mdash; IPFML v0.3.0 documentation</title>
+  <title>Search &mdash; IPFML v0.3.1 documentation</title>
   
 
   
@@ -56,7 +56,7 @@
             
             
               <div class="version">
-                0.3.0
+                0.3.1
               </div>
             
           

File diff suppressed because it is too large
+ 1 - 1
docs/build/html/searchindex.js


+ 2 - 2
docs/source/conf.py

@@ -24,9 +24,9 @@ copyright = '2019, Jérôme BUISINE'
 author = 'Jérôme BUISINE'
 
 # The short X.Y version
-version = '0.3.0'
+version = '0.3.1'
 # The full versiabson, including alpha/beta/rc tags
-release = 'v0.3.0'
+release = 'v0.3.1'
 
 
 # -- General configuration ---------------------------------------------------

+ 191 - 70
ipfml/processing.py

@@ -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)

+ 1 - 1
setup.py

@@ -37,7 +37,7 @@ class BuildTestCommand(setuptools.command.build_py.build_py):
 
 setup(
     name='ipfml',
-    version='0.3.0',
+    version='0.3.1',
     description='Image Processing For Machine Learning',
     long_description=readme(),
     classifiers=[