Repository: dask/dask

Issue:
Additional improvement for da.image.imread
I think following 2 improvements make the function better.
#### 1. Allow custom `imread` function.

Some prefer `opencv` which reads color in BGR order, otherwise `skimage` reads in RGB order. Adding `dialect` option (like `dialect='skimage'` or `dialect='cv'`) or accept different file read function may better.
#### 2. Allow custom preprocessing function.

In image processing, input images may have different sizes. In these case, preprocessing is needed between image read and array creation. This preprocessing function must return the same size of array on user's responsibility.



Discussion:

Resolving patch:
diff --git a/dask/array/image.py b/dask/array/image.py
--- a/dask/array/image.py
+++ b/dask/array/image.py
@@ -13,7 +13,7 @@ def add_leading_dimension(x):
     return x[None, ...]
 
 
-def imread(filename):
+def imread(filename, imread=None, preprocess=None):
     """ Read a stack of images into a dask array
 
     Parameters
@@ -21,6 +21,13 @@ def imread(filename):
 
     filename: string
         A globstring like 'myfile.*.png'
+    imread: function (optional)
+        Optionally provide custom imread function.
+        Function should expect a filename and produce a numpy array.
+        Defaults to ``skimage.io.imread``.
+    preprocess: function (optional)
+        Optionally provide custom function to preprocess the image.
+        Function should expect a numpy array for a single image.
 
     Example
     -------
@@ -36,17 +43,25 @@ def imread(filename):
     Dask array of all images stacked along the first dimension.  All images
     will be treated as individual chunks
     """
+    imread = imread or sk_imread
     filenames = sorted(glob(filename))
     if not filenames:
         raise ValueError("No files found under name %s" % filename)
 
     name = 'imread-%s' % tokenize(filenames, map(os.path.getmtime, filenames))
 
-    sample = sk_imread(filenames[0])
-
-    dsk = dict(((name, i) + (0,) * len(sample.shape),
-                (add_leading_dimension, (sk_imread, filename)))
-                for i, filename in enumerate(filenames))
+    sample = imread(filenames[0])
+    if preprocess:
+        sample = preprocess(sample)
+
+    keys = [(name, i) + (0,) * len(sample.shape) for i in range(len(filenames))]
+    if preprocess:
+        values = [(add_leading_dimension, (preprocess, (imread, filename)))
+                  for filename in filenames]
+    else:
+        values = [(add_leading_dimension, (imread, filename))
+                  for filename in filenames]
+    dsk = dict(zip(keys, values))
 
     chunks = ((1,) * len(filenames),) + tuple((d,) for d in sample.shape)
 


Test patch:
diff --git a/dask/array/tests/test_image.py b/dask/array/tests/test_image.py
--- a/dask/array/tests/test_image.py
+++ b/dask/array/tests/test_image.py
@@ -33,3 +33,20 @@ def test_imread():
 
         assert im.compute().shape == (4, 5, 6, 3)
         assert im.compute().dtype == 'uint8'
+
+
+def test_imread_with_custom_function():
+    def imread2(fn):
+        return np.ones((2, 3, 4), dtype='i1')
+    with random_images(4, (5, 6, 3)) as globstring:
+        im = da_imread(globstring, imread=imread2)
+        assert (im.compute() == np.ones((4, 2, 3, 4), dtype='i1')).all()
+
+
+def test_preprocess():
+    def preprocess(x):
+        x[:] = 1
+        return x[:, :, 0]
+    with random_images(4, (2, 3, 4)) as globstring:
+        im = da_imread(globstring, preprocess=preprocess)
+        assert (im.compute() == np.ones((4, 2, 3), dtype='i1')).all()