Parcourir la source

Merge branch 'release/v0.1.3'

Jerome Buisine il y a 5 ans
Parent
commit
11158700b9
3 fichiers modifiés avec 101 ajouts et 88 suppressions
  1. 39 38
      ipfml/image_processing.py
  2. 60 48
      ipfml/metrics.py
  3. 2 2
      setup.py

+ 39 - 38
ipfml/image_processing.py

@@ -120,11 +120,8 @@ def divide_in_blocks(image, block_size, pil=True):
     blocks = []
     mode = 'RGB'
 
-    # check input type (PIL Image or numpy array) and convert it if necessary
-    if hasattr(image, 'filename'):
-        image_array = np.array(image)
-    else:
-        image_array = image
+    # convert in numpy array
+    image_array = np.array(image)
 
     # check dimension of input image
     if image_array.ndim != 3:
@@ -132,13 +129,13 @@ def divide_in_blocks(image, block_size, pil=True):
         image_width, image_height = image_array.shape
     else:
         image_width, image_height, _ = image_array.shape
-        
+
     # check size compatibility
     width, height = block_size
 
     if(image_width % width != 0):
         raise "Width size issue, block size not compatible"
-    
+
     if(image_height % height != 0):
         raise "Height size issue, block size not compatible"
 
@@ -149,7 +146,7 @@ def divide_in_blocks(image, block_size, pil=True):
 
         begin_x = i * width
 
-        for j in range(int(nb_block_height)): 
+        for j in range(int(nb_block_height)):
 
             begin_y = j * height
 
@@ -163,7 +160,7 @@ def divide_in_blocks(image, block_size, pil=True):
 
     return blocks
 
-    
+
 def normalize_arr(arr):
     '''
     @brief Normalize data of 1D array shape
@@ -185,7 +182,7 @@ def normalize_arr(arr):
 
     for v in arr:
          output_arr.append((v - min_value) / (max_value - min_value))
-    
+
     return output_arr
 
 
@@ -203,12 +200,12 @@ def normalize_arr_with_range(arr, min, max):
     >>> arr_normalized[1]
     0.05
     '''
-    
+
     output_arr = []
 
     for v in arr:
         output_arr.append((v - min) / (max - min))
-    
+
     return output_arr
 
 def normalize_2D_arr(arr):
@@ -217,7 +214,7 @@ def normalize_2D_arr(arr):
     @param 2D numpy array
 
     Usage :
-    
+
     >>> from PIL import Image
     >>> from ipfml import image_processing
     >>> img = Image.open('./images/test_img.png')
@@ -230,17 +227,17 @@ def normalize_2D_arr(arr):
     # getting min and max value from 2D array
     max_value = arr.max(axis=1).max()
     min_value = arr.min(axis=1).min()
-    
+
     # lambda computation to normalize
     g = lambda x : (x - min_value) / (max_value - min_value)
     f = np.vectorize(g)
-    
+
     return f(arr)
 
 def rgb_to_mscn(image):
     """
     @brief Convert RGB Image into Mean Subtracted Contrast Normalized (MSCN)
-    @param 3D RGB image numpy array or PIL RGB image 
+    @param 3D RGB image numpy array or PIL RGB image
 
     Usage :
 
@@ -257,21 +254,13 @@ def rgb_to_mscn(image):
 
     # convert rgb image to gray
     im = np.array(color.rgb2gray(img_arr)*255, 'uint8')
-    
-    s = 7/6
-    blurred = cv2.GaussianBlur(im, (7, 7), s) # apply gaussian blur to the image
-    blurred_sq = blurred * blurred 
-    sigma = cv2.GaussianBlur(im * im, (7, 7), s)  # switch to -3, 3 (7, 7) before..
-    sigma = abs(sigma - blurred_sq) ** 0.5
-    sigma = sigma + 1.0/255 # to make sure the denominator doesn't give DivideByZero Exception
-    structdis = (im - blurred)/sigma # final MSCN(i, j) image
 
-    return structdis
+    return metrics.gray_to_mscn(im)
 
 def rgb_to_grey_low_bits(image, bind=15):
     """
     @brief Convert RGB Image into grey image using only 4 low bits values
-    @param 3D RGB image numpy array or PIL RGB image 
+    @param 3D RGB image numpy array or PIL RGB image
 
     Usage :
 
@@ -285,9 +274,29 @@ def rgb_to_grey_low_bits(image, bind=15):
 
     img_arr = np.array(image)
     grey_block = np.array(color.rgb2gray(img_arr)*255, 'uint8')
-    
+
     return metrics.get_low_bits_img(grey_block, bind)
 
+def rgb_to_LAB_L_low_bits(image, bind=15):
+    """
+    @brief Convert RGB Image into Lab L channel image using only 4 low bits values
+    @param 3D RGB image numpy array or PIL RGB image
+
+    Usage :
+
+    >>> from PIL import Image
+    >>> from ipfml import image_processing
+    >>> img = Image.open('./images/test_img.png')
+    >>> low_bits_Lab_l_img = image_processing.rgb_to_Lab_L_low_bits(img)
+    >>> 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, bind)
+
+
 # TODO : Check this method too...
 def get_random_active_block(blocks, threshold = 0.1):
     """
@@ -312,7 +321,7 @@ def get_random_active_block(blocks, threshold = 0.1):
 
 
 # TODO : check this method and check how to use active block
-def segment_relation_in_block(block, active_block):   
+def segment_relation_in_block(block, active_block):
     """
     @brief Return bêta value to quantity relation between central segment and surrouding regions into block
     @param 2D numpy array
@@ -342,10 +351,6 @@ def segment_relation_in_block(block, active_block):
     std_cen = np.std(central_segments.flatten())
     std_block = np.std(block.flatten())
 
-    print("CEN " + str(std_cen))
-    print("SUR " + str(std_sur))
-    print("BLOCK " + str(std_block))
-
     std_q = std_cen / std_sur
 
     # from article, it says that block if affected with noise if (std_block > 2 * beta)
@@ -361,7 +366,7 @@ def normalize_kernel(kernel):
 
 def gaussian_kernel2d(n, sigma):
     Y, X = np.indices((n, n)) - int(n/2)
-    gaussian_kernel = 1 / (2 * np.pi * sigma ** 2) * np.exp(-(X ** 2 + Y ** 2) / (2 * sigma ** 2)) 
+    gaussian_kernel = 1 / (2 * np.pi * sigma ** 2) * np.exp(-(X ** 2 + Y ** 2) / (2 * sigma ** 2))
     return normalize_kernel(gaussian_kernel)
 
 def local_mean(image, kernel):
@@ -378,14 +383,10 @@ def calculate_mscn_coefficients(image, kernel_size=6, sigma=7/6):
     # check if PIL image or not
     img_arr = np.array(image)
 
-    #im = np.array(color.rgb2gray(img_arr)*255, 'uint8')
-    #im = np.asarray(cv2.imread(image.filename, 0)) # read as gray scale
-    print(img_arr.shape)
-
     C = 1/255
     kernel = gaussian_kernel2d(kernel_size, sigma=sigma)
     local_mean = signal.convolve2d(img_arr, kernel, 'same')
     local_var = local_deviation(img_arr, local_mean, kernel)
-    
+
     return (img_arr - local_mean) / (local_var + C)
 

+ 60 - 48
ipfml/metrics.py

@@ -7,6 +7,8 @@ import numpy as np
 from sklearn import preprocessing
 from skimage import io, color
 
+import cv2
+
 def get_image_path(image):
     """
     @brief Returns file path of PIL Image
@@ -20,11 +22,11 @@ def get_image_path(image):
     >>> 'images/test_img.png' in path
     True
     """
-    
+
     if hasattr(image, 'filename'):
         file_path = image.filename
     else:
-        raise Exception("Image provided is not correct, required filename property...")    
+        raise Exception("Image provided is not correct, required filename property...")
 
     return file_path
 
@@ -33,8 +35,8 @@ def get_SVD(image):
     @brief Transforms Image into SVD
     @param image to convert
     @return U, s, V image decomposition
-    
-    Usage : 
+
+    Usage :
 
     >>> from PIL import Image
     >>> from ipfml import metrics
@@ -55,7 +57,7 @@ def get_SVD_s(image):
     @param image to convert
     @return s
 
-    Usage : 
+    Usage :
 
     >>> from PIL import Image
     >>> from ipfml import metrics
@@ -78,9 +80,9 @@ def get_SVD_U(image):
     >>> from PIL import Image
     >>> from ipfml import metrics
     >>> img = Image.open('./images/test_img.png')
-    >>> Lab = metrics.get_LAB(img)
-    >>> Lab.shape
-    (200, 200, 3)
+    >>> U = metrics.get_SVD_U(img)
+    >>> U.shape
+    (200, 200)
     """
 
     U, s, V = svd(image, full_matrices=False)
@@ -91,8 +93,8 @@ def get_SVD_V(image):
     @brief Transforms Image into SVD and returns only 'V' part
     @param image to convert
     @return V
-    
-    Usage : 
+
+    Usage :
 
     >>> from PIL import Image
     >>> from ipfml import metrics
@@ -107,11 +109,11 @@ def get_SVD_V(image):
 
 def get_LAB(image):
     """
-    @brief Transforms PIL RGB Image into LAB 
+    @brief Transforms PIL RGB Image into LAB
     @param image to convert
     @return Lab information
 
-    Usage : 
+    Usage :
 
     >>> from PIL import Image
     >>> from ipfml import metrics
@@ -121,16 +123,14 @@ def get_LAB(image):
     (200, 200, 3)
     """
 
-    file_path = get_image_path(image)
-    rgb = io.imread(file_path)
-    return color.rgb2lab(rgb)
+    return color.rgb2lab(image)
 
 def get_LAB_L(image):
     """
     @brief Transforms PIL RGB Image into LAB and returns L
     @param image to convert
     @return Lab information
-    
+
     >>> from PIL import Image
     >>> from ipfml import metrics
     >>> img = Image.open('./images/test_img.png')
@@ -138,10 +138,8 @@ def get_LAB_L(image):
     >>> L.shape
     (200, 200)
     """
-    
-    file_path = get_image_path(image)
-    rgb = io.imread(file_path)
-    lab = color.rgb2lab(rgb)
+
+    lab = get_LAB(image)
     return lab[:, :, 0]
 
 def get_LAB_A(image):
@@ -149,8 +147,8 @@ def get_LAB_A(image):
     @brief Transforms PIL RGB Image into LAB and returns A
     @param image to convert
     @return Lab information
-    
-    Usage : 
+
+    Usage :
 
     >>> from PIL import Image
     >>> from ipfml import metrics
@@ -160,9 +158,7 @@ def get_LAB_A(image):
     (200, 200)
     """
 
-    file_path = get_image_path(image)
-    rgb = io.imread(file_path)
-    lab = color.rgb2lab(rgb)
+    lab = get_LAB(image)
     return lab[:, :, 1]
 
 def get_LAB_B(image):
@@ -170,8 +166,8 @@ def get_LAB_B(image):
     @brief Transforms PIL RGB Image into LAB and returns B
     @param image to convert
     @return Lab information
-    
-    Usage : 
+
+    Usage :
 
     >>> from PIL import Image
     >>> from ipfml import metrics
@@ -180,10 +176,8 @@ def get_LAB_B(image):
     >>> B.shape
     (200, 200)
     """
-   
-    file_path = get_image_path(image)
-    rgb = io.imread(file_path)
-    lab = color.rgb2lab(rgb)
+
+    lab = get_LAB(image)
     return lab[:, :, 2]
 
 def get_XYZ(image):
@@ -191,8 +185,8 @@ def get_XYZ(image):
     @brief Transforms PIL RGB Image into XYZ
     @param image to convert
     @return Lab information
-    
-    Usage : 
+
+    Usage :
 
     >>> from PIL import Image
     >>> from ipfml import metrics
@@ -201,9 +195,7 @@ def get_XYZ(image):
     (200, 200, 3)
     """
 
-    file_path = get_image_path(image)
-    rgb = io.imread(file_path)
-    return color.rgb2xyz(rgb)
+    return color.rgb2xyz(image)
 
 def get_XYZ_X(image):
     """
@@ -211,7 +203,7 @@ def get_XYZ_X(image):
     @param image to convert
     @return Lab information
 
-    Usage : 
+    Usage :
 
     >>> from PIL import Image
     >>> from ipfml import metrics
@@ -221,9 +213,7 @@ def get_XYZ_X(image):
     (200, 200)
     """
 
-    file_path = get_image_path(image)
-    rgb = io.imread(file_path)
-    xyz = color.rgb2xyz(rgb)
+    xyz = color.rgb2xyz(image)
     return xyz[:, :, 0]
 
 def get_XYZ_Y(image):
@@ -242,9 +232,7 @@ def get_XYZ_Y(image):
     (200, 200)
     """
 
-    file_path = get_image_path(image)
-    rgb = io.imread(file_path)
-    xyz = color.rgb2xyz(rgb)
+    xyz = color.rgb2xyz(image)
     return xyz[:, :, 1]
 
 def get_XYZ_Z(image):
@@ -253,7 +241,7 @@ def get_XYZ_Z(image):
     @param image to convert
     @return Lab information
 
-    Usage : 
+    Usage :
 
     >>> from PIL import Image
     >>> from ipfml import metrics
@@ -263,9 +251,7 @@ def get_XYZ_Z(image):
     (200, 200)
     """
 
-    file_path = get_image_path(image)
-    rgb = io.imread(file_path)
-    xyz = color.rgb2xyz(rgb)
+    xyz = color.rgb2xyz(image)
     return xyz[:, :, 2]
 
 def get_low_bits_img(image, bind=15):
@@ -284,7 +270,33 @@ def get_low_bits_img(image, bind=15):
     >>> low_bits_img.shape
     (200, 200, 3)
     """
-    
+
     img_arr = np.array(image)
 
     return img_arr & bind
+
+
+def gray_to_mscn(image):
+    """
+    @brief Convert Grayscale Image into Mean Subtracted Contrast Normalized (MSCN)
+    @param grayscale image numpy array or PIL RGB image
+
+    Usage :
+
+    >>> from PIL import Image
+    >>> from ipfml import image_processing
+    >>> img = Image.open('./images/test_img.png')
+    >>> img_mscn = image_processing.rgb_to_mscn(img)
+    >>> img_mscn.shape
+    (200, 200)
+    """
+
+    s = 7/6
+    blurred = cv2.GaussianBlur(image, (7, 7), s) # apply gaussian blur to the image
+    blurred_sq = blurred * blurred
+    sigma = cv2.GaussianBlur(image * image, (7, 7), s)
+    sigma = abs(sigma - blurred_sq) ** 0.5
+    sigma = sigma + 1.0/255 # avoid DivideByZero Exception
+    mscn = (image - blurred)/sigma # MSCN(i, j) image
+
+    return mscn

+ 2 - 2
setup.py

@@ -21,7 +21,7 @@ class BuildTestCommand(setuptools.command.build_py.build_py):
     setuptools.command.build_py.build_py.run(self)
 
 setup(name='IPFML',
-      version='0.1.2',
+      version='0.1.3',
       description='Image Processing For Machine Learning',
       long_description=readme(),
       classifiers=[
@@ -48,4 +48,4 @@ setup(name='IPFML',
       cmdclass={
         'build_py': BuildTestCommand,
       },
-      zip_safe=False)
+      zip_safe=False)