[arrayfire] 154/248: FEAT add loadImageT and saveImageT. Provides loading in different types

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Tue Nov 17 15:54:18 UTC 2015


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch dfsg-clean
in repository arrayfire.

commit 61226f3ed7abf08afb6965715e6a273fad1c7f71
Author: Shehzan Mohammed <shehzan at arrayfire.com>
Date:   Thu Oct 29 16:55:16 2015 -0400

    FEAT add loadImageT and saveImageT. Provides loading in different types
    
    * Allows loading and saving images as u8, u16 and u32
---
 include/af/image.h         |  52 +++++++
 src/api/c/imageio2.cpp     | 370 +++++++++++++++++++++++++++++++++++++++++++++
 src/api/c/imageio_helper.h |   5 +-
 src/api/cpp/imageio.cpp    |  12 ++
 4 files changed, 435 insertions(+), 4 deletions(-)

diff --git a/include/af/image.h b/include/af/image.h
index 6c0ef76..eef3185 100644
--- a/include/af/image.h
+++ b/include/af/image.h
@@ -96,6 +96,31 @@ AFAPI void* saveImageMem(const array& in, const imageFormat format = AF_FIF_PNG)
 AFAPI void deleteImageMem(void *ptr);
 #endif
 
+#if AF_API_VERSION >= 32
+/**
+    C++ Interface for loading an image as is original type
+
+    \param[in] filename is name of file to be loaded
+    \return image loaded as \ref af::array()
+
+    \ingroup imageio_func_load
+*/
+AFAPI array loadImageT(const char* filename);
+#endif
+
+#if AF_API_VERSION >= 32
+/**
+    C++ Interface for saving an image without modifications
+
+    \param[in] filename is name of file to be saved
+    \param[in] in is the array to be saved. Should be u8 for saving 8-bit image,
+    u16 for 16-bit image, and f32 for 32-bit image.
+
+    \ingroup imageio_func_load
+*/
+AFAPI void saveImageT(const char* filename, const array& in);
+#endif
+
 /**
     C++ Interface for resizing an image to specified dimensions
 
@@ -689,6 +714,33 @@ extern "C" {
     AFAPI af_err af_delete_image_memory(void* ptr);
 #endif
 
+#if AF_API_VERSION >= 32
+    /**
+        C Interface for loading an image as is original type
+
+        \param[in] filename is name of file to be loaded
+        \return     \ref AF_SUCCESS if successful
+
+        \ingroup imageio_func_load
+    */
+    AFAPI af_err af_load_image_t(af_array *out, const char* filename);
+#endif
+
+#if AF_API_VERSION >= 32
+    /**
+        C Interface for saving an image without modifications
+
+        \param[in] filename is name of file to be saved
+        \param[in] in is the array to be saved. Should be u8 for saving 8-bit image,
+        u16 for 16-bit image, and f32 for 32-bit image.
+
+        \return     \ref AF_SUCCESS if successful
+
+        \ingroup imageio_func_load
+    */
+    AFAPI af_err af_save_image_t(const char* filename, const af_array in);
+#endif
+
     /**
        C Interface for resizing an image to specified dimensions
 
diff --git a/src/api/c/imageio2.cpp b/src/api/c/imageio2.cpp
new file mode 100644
index 0000000..6075ffc
--- /dev/null
+++ b/src/api/c/imageio2.cpp
@@ -0,0 +1,370 @@
+/*******************************************************
+ * Copyright (c) 2014, ArrayFire
+ * All rights reserved.
+ *
+ * This file is distributed under 3-clause BSD license.
+ * The complete license agreement can be obtained at:
+ * http://arrayfire.com/licenses/BSD-3-Clause
+ ********************************************************/
+
+#if defined(WITH_FREEIMAGE)
+
+#include "imageio_helper.h"
+
+#include <af/array.h>
+#include <af/index.h>
+#include <af/dim4.hpp>
+#include <af/arith.h>
+#include <af/algorithm.h>
+#include <af/blas.h>
+#include <af/data.h>
+#include <af/image.h>
+#include <backend.hpp>
+#include <ArrayInfo.hpp>
+#include <traits.hpp>
+#include <memory.hpp>
+
+#include <string>
+#include <cstring>
+#include <cstdio>
+#include <cstdlib>
+
+using af::dim4;
+using namespace detail;
+
+template<typename T, FI_CHANNELS fi_color>
+static af_err readImage_t(af_array *rImage, const uchar* pSrcLine, const int nSrcPitch,
+                            const uint fi_w, const uint fi_h)
+{
+    // create an array to receive the loaded image data.
+    AF_CHECK(af_init());
+    T *pDst = pinnedAlloc<T>(fi_w * fi_h * 4); // 4 channels is max
+    T* pDst0 = pDst;
+    T* pDst1 = pDst + (fi_w * fi_h * 1);
+    T* pDst2 = pDst + (fi_w * fi_h * 2);
+    T* pDst3 = pDst + (fi_w * fi_h * 3);
+
+    int offR = 2; int offG = 1; int offB = 0; int offA = 3;
+    uint indx = 0;
+    uint step = fi_color;
+
+    for (uint x = 0; x < fi_w; ++x) {
+        for (uint y = 0; y < fi_h; ++y) {
+            const T *src = (T*)(pSrcLine - y * nSrcPitch);
+                               pDst2[indx] = (T) *(src + (x * step + offB));
+            if (fi_color >= 3) pDst1[indx] = (T) *(src + (x * step + offG));
+            if (fi_color >= 3) pDst0[indx] = (T) *(src + (x * step + offR));
+            if (fi_color == 4) pDst3[indx] = (T) *(src + (x * step + offA));
+            indx++;
+        }
+    }
+
+    // TODO
+    af::dim4 dims(fi_h, fi_w, fi_color, 1);
+    af_err err = af_create_array(rImage, pDst, dims.ndims(), dims.get(),
+                                 (af_dtype) af::dtype_traits<T>::af_type);
+    pinnedFree(pDst);
+    return err;
+}
+
+FREE_IMAGE_TYPE getFIT(FI_CHANNELS channels, af_dtype type)
+{
+    if(channels == AFFI_GRAY) {
+             if(type == u8 ) return FIT_BITMAP;
+        else if(type == u16) return FIT_UINT16;
+        else if(type == f32) return FIT_FLOAT;
+    } else if(channels == AFFI_RGB) {
+             if(type == u8 ) return FIT_BITMAP;
+        else if(type == u16) return FIT_RGB16;
+        else if(type == f32) return FIT_RGBF;
+    } else if(channels == AFFI_RGBA) {
+             if(type == u8 ) return FIT_BITMAP;
+        else if(type == u16) return FIT_RGBA16;
+        else if(type == f32) return FIT_RGBAF;
+    }
+    return FIT_BITMAP;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// File IO
+////////////////////////////////////////////////////////////////////////////////
+// Load image from disk.
+af_err af_load_image_t(af_array *out, const char* filename)
+{
+    try {
+        ARG_ASSERT(1, filename != NULL);
+
+        // for statically linked FI
+        FI_Init();
+
+        // set your own FreeImage error handler
+        FreeImage_SetOutputMessage(FreeImageErrorHandler);
+
+        // try to guess the file format from the file extension
+        FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(filename);
+        if (fif == FIF_UNKNOWN) {
+            fif = FreeImage_GetFIFFromFilename(filename);
+        }
+
+        if(fif == FIF_UNKNOWN) {
+            AF_ERROR("FreeImage Error: Unknown File or Filetype", AF_ERR_NOT_SUPPORTED);
+        }
+
+        int flags = 0;
+        if(fif == FIF_JPEG) flags = flags | JPEG_ACCURATE;
+
+        // check that the plugin has reading capabilities ...
+        FIBITMAP* pBitmap = NULL;
+        if (FreeImage_FIFSupportsReading(fif)) {
+            pBitmap = FreeImage_Load(fif, filename, flags);
+        }
+
+        if(pBitmap == NULL) {
+            AF_ERROR("FreeImage Error: Error reading image or file does not exist", AF_ERR_RUNTIME);
+        }
+
+        // make sure pBitmap is unleaded automatically, no matter how we exit this function
+        FI_BitmapResource bitmapUnloader(pBitmap);
+
+        // check image color type
+        uint color_type = FreeImage_GetColorType(pBitmap);
+        const uint fi_bpp = FreeImage_GetBPP(pBitmap);
+        //int fi_color = (int)((fi_bpp / 8.0) + 0.5);        //ceil
+        int fi_color;
+        switch(color_type) {
+            case 0:                     // FIC_MINISBLACK
+            case 1:                     // FIC_MINISWHITE
+                fi_color = 1; break;
+            case 2:                     // FIC_PALETTE
+            case 3:                     // FIC_RGB
+                fi_color = 3; break;
+            case 4:                     // FIC_RGBALPHA
+            case 5:                     // FIC_CMYK
+                fi_color = 4; break;
+            default:                    // Should not come here
+                fi_color = 3; break;
+        }
+
+        const int fi_bpc = fi_bpp / fi_color;
+        if(fi_bpc != 8 && fi_bpc != 16 && fi_bpc != 32) {
+            AF_ERROR("FreeImage Error: Bits per channel not supported", AF_ERR_NOT_SUPPORTED);
+        }
+
+        // sizes
+        uint fi_w = FreeImage_GetWidth(pBitmap);
+        uint fi_h = FreeImage_GetHeight(pBitmap);
+
+        // FI = row major | AF = column major
+        uint nSrcPitch = FreeImage_GetPitch(pBitmap);
+        const uchar* pSrcLine = FreeImage_GetBits(pBitmap) + nSrcPitch * (fi_h - 1);
+
+        // result image
+        af_array rImage;
+        if(fi_color == 4) {     //4 channel image
+            if(fi_bpc == 8)
+                AF_CHECK((readImage_t<uchar,  AFFI_RGBA>)(&rImage, pSrcLine, nSrcPitch, fi_w, fi_h));
+            else if(fi_bpc == 16)
+                AF_CHECK((readImage_t<ushort, AFFI_RGBA>)(&rImage, pSrcLine, nSrcPitch, fi_w, fi_h));
+            else if(fi_bpc == 32)
+                AF_CHECK((readImage_t<float,  AFFI_RGBA>)(&rImage, pSrcLine, nSrcPitch, fi_w, fi_h));
+        } else if (fi_color == 1) {
+            if(fi_bpc == 8)
+                AF_CHECK((readImage_t<uchar,  AFFI_GRAY>)(&rImage, pSrcLine, nSrcPitch, fi_w, fi_h));
+            else if(fi_bpc == 16)
+                AF_CHECK((readImage_t<ushort, AFFI_GRAY>)(&rImage, pSrcLine, nSrcPitch, fi_w, fi_h));
+            else if(fi_bpc == 32)
+                AF_CHECK((readImage_t<float,  AFFI_GRAY>)(&rImage, pSrcLine, nSrcPitch, fi_w, fi_h));
+        } else {             //3 channel imag
+            if(fi_bpc == 8)
+                AF_CHECK((readImage_t<uchar,  AFFI_RGB >)(&rImage, pSrcLine, nSrcPitch, fi_w, fi_h));
+            else if(fi_bpc == 16)
+                AF_CHECK((readImage_t<ushort, AFFI_RGB >)(&rImage, pSrcLine, nSrcPitch, fi_w, fi_h));
+            else if(fi_bpc == 32)
+                AF_CHECK((readImage_t<float,  AFFI_RGB >)(&rImage, pSrcLine, nSrcPitch, fi_w, fi_h));
+        }
+
+        std::swap(*out,rImage);
+    } CATCHALL;
+
+    return AF_SUCCESS;
+}
+
+template<typename T, FI_CHANNELS channels>
+static void save_t(T* pDstLine, const af_array in, const dim4 dims, uint nDstPitch)
+{
+    af_array rr = 0, gg = 0, bb = 0, aa = 0;
+    AF_CHECK(channel_split(in, dims, &rr, &gg, &bb, &aa)); // convert array to 3 channels if needed
+
+    af_array rrT = 0, ggT = 0, bbT = 0, aaT = 0;
+    T *pSrc0 = 0, *pSrc1 = 0, *pSrc2 = 0, *pSrc3 = 0;
+
+    uint step = channels; // force 3 channels saving
+    uint indx = 0;
+
+                      AF_CHECK(af_transpose(&rrT, rr, false));
+    if(channels >= 3) AF_CHECK(af_transpose(&ggT, gg, false));
+    if(channels >= 3) AF_CHECK(af_transpose(&bbT, bb, false));
+    if(channels >= 4) AF_CHECK(af_transpose(&aaT, aa, false));
+
+    ArrayInfo cinfo = getInfo(rrT);
+                      pSrc0 = pinnedAlloc<T>(cinfo.elements());
+    if(channels >= 3) pSrc1 = pinnedAlloc<T>(cinfo.elements());
+    if(channels >= 3) pSrc2 = pinnedAlloc<T>(cinfo.elements());
+    if(channels >= 4) pSrc3 = pinnedAlloc<T>(cinfo.elements());
+
+                      AF_CHECK(af_get_data_ptr((void*)pSrc0, rrT));
+    if(channels >= 3) AF_CHECK(af_get_data_ptr((void*)pSrc1, ggT));
+    if(channels >= 3) AF_CHECK(af_get_data_ptr((void*)pSrc2, bbT));
+    if(channels >= 4) AF_CHECK(af_get_data_ptr((void*)pSrc3, aaT));
+
+    const uint fi_w = dims[1];
+    const uint fi_h = dims[0];
+
+    // Copy the array into FreeImage buffer
+    for (uint y = 0; y < fi_h; ++y) {
+        for (uint x = 0; x < fi_w; ++x) {
+            if(channels == 1) {
+                *(pDstLine + x * step + 0) = (T) pSrc0[indx]; // b -> 0
+            } else if(channels >=3) {
+                *(pDstLine + x * step + 0) = (T) pSrc2[indx]; // b -> 0
+                *(pDstLine + x * step + 1) = (T) pSrc1[indx]; // g -> 1
+                *(pDstLine + x * step + 2) = (T) pSrc0[indx]; // r -> 2
+            }
+            if(channels >= 4) *(pDstLine + x * step + 3) = (T) pSrc3[indx]; // a
+            ++indx;
+        }
+        pDstLine = (T*)(((uchar*)pDstLine) - nDstPitch);
+    }
+                      pinnedFree(pSrc0);
+    if(channels >= 3) pinnedFree(pSrc1);
+    if(channels >= 3) pinnedFree(pSrc2);
+    if(channels >= 4) pinnedFree(pSrc3);
+
+    if(rr != 0) AF_CHECK(af_release_array(rr ));
+    if(gg != 0) AF_CHECK(af_release_array(gg ));
+    if(bb != 0) AF_CHECK(af_release_array(bb ));
+    if(aa != 0) AF_CHECK(af_release_array(aa ));
+    if(rrT!= 0) AF_CHECK(af_release_array(rrT));
+    if(ggT!= 0) AF_CHECK(af_release_array(ggT));
+    if(bbT!= 0) AF_CHECK(af_release_array(bbT));
+    if(aaT!= 0) AF_CHECK(af_release_array(aaT));
+}
+
+// Save an image to disk.
+af_err af_save_image_t(const char* filename, const af_array in)
+{
+    try {
+
+        ARG_ASSERT(0, filename != NULL);
+
+        FI_Init();
+
+        // set your own FreeImage error handler
+        FreeImage_SetOutputMessage(FreeImageErrorHandler);
+
+        // try to guess the file format from the file extension
+        FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(filename);
+        if (fif == FIF_UNKNOWN) {
+            fif = FreeImage_GetFIFFromFilename(filename);
+        }
+
+        if(fif == FIF_UNKNOWN) {
+            AF_ERROR("FreeImage Error: Unknown Filetype", AF_ERR_NOT_SUPPORTED);
+        }
+
+        ArrayInfo info = getInfo(in);
+        // check image color type
+        FI_CHANNELS channels = (FI_CHANNELS)info.dims()[2];
+        DIM_ASSERT(1, channels <= 4);
+        DIM_ASSERT(1, channels != 2);
+
+        // sizes
+        uint fi_w = info.dims()[1];
+        uint fi_h = info.dims()[0];
+
+        af_dtype type = info.getType();
+
+        // FI assumes [0-255] for u8
+        // FI assumes [0-65k] for u16
+        // FI assumes [0-1]   for f32
+        int fi_bpp = 0;
+        switch(type) {
+            case u8:  fi_bpp = channels * 8; break;
+            case u16: fi_bpp = channels * 16; break;
+            case f32: fi_bpp = channels * 32; break;
+            default: TYPE_ERROR(1, type);
+        }
+
+        FREE_IMAGE_TYPE fit_type = getFIT(channels, type);
+
+        // create the result image storage using FreeImage
+        FIBITMAP* pResultBitmap = NULL;
+        switch(type) {
+            case u8:  pResultBitmap = FreeImage_AllocateT(fit_type, fi_w, fi_h, fi_bpp); break;
+            case u16: pResultBitmap = FreeImage_AllocateT(fit_type, fi_w, fi_h, fi_bpp); break;
+            case f32: pResultBitmap = FreeImage_AllocateT(fit_type, fi_w, fi_h, fi_bpp); break;
+            default: TYPE_ERROR(1, type);
+        }
+
+        if(pResultBitmap == NULL) {
+            AF_ERROR("FreeImage Error: Error creating image or file", AF_ERR_RUNTIME);
+        }
+
+        // make sure pResultBitmap is unloaded automatically, no matter how we exit this function
+        FI_BitmapResource resultBitmapUnloader(pResultBitmap);
+
+        // FI = row major | AF = column major
+        uint nDstPitch = FreeImage_GetPitch(pResultBitmap);
+        void* pDstLine = FreeImage_GetBits(pResultBitmap) + nDstPitch * (fi_h - 1);
+
+        if(channels == AFFI_GRAY) {
+            switch(type) {
+                case u8:  save_t<uchar , AFFI_GRAY>((uchar *)pDstLine, in, info.dims(), nDstPitch); break;
+                case u16: save_t<ushort, AFFI_GRAY>((ushort*)pDstLine, in, info.dims(), nDstPitch); break;
+                case f32: save_t<float , AFFI_GRAY>((float *)pDstLine, in, info.dims(), nDstPitch); break;
+                default: TYPE_ERROR(1, type);
+            }
+        } else if(channels == AFFI_RGB) {
+            switch(type) {
+                case u8:  save_t<uchar , AFFI_RGB >((uchar *)pDstLine, in, info.dims(), nDstPitch); break;
+                case u16: save_t<ushort, AFFI_RGB >((ushort*)pDstLine, in, info.dims(), nDstPitch); break;
+                case f32: save_t<float , AFFI_RGB >((float *)pDstLine, in, info.dims(), nDstPitch); break;
+                default: TYPE_ERROR(1, type);
+            }
+        } else {
+            switch(type) {
+                case u8:  save_t<uchar , AFFI_RGBA>((uchar *)pDstLine, in, info.dims(), nDstPitch); break;
+                case u16: save_t<ushort, AFFI_RGBA>((ushort*)pDstLine, in, info.dims(), nDstPitch); break;
+                case f32: save_t<float , AFFI_RGBA>((float *)pDstLine, in, info.dims(), nDstPitch); break;
+                default: TYPE_ERROR(1, type);
+            }
+        }
+
+        int flags = 0;
+        if(fif == FIF_JPEG) flags = flags | JPEG_QUALITYSUPERB;
+
+        // now save the result image
+        if (!(FreeImage_Save(fif, pResultBitmap, filename, flags) == TRUE)) {
+            AF_ERROR("FreeImage Error: Failed to save image", AF_ERR_RUNTIME);
+        }
+
+    } CATCHALL
+
+    return AF_SUCCESS;
+}
+
+#else   // WITH_FREEIMAGE
+#include <af/image.h>
+#include <stdio.h>
+af_err af_load_image_t(af_array *out, const char* filename, const bool isColor)
+{
+    printf("Error: Image IO requires FreeImage. See https://github.com/arrayfire/arrayfire\n");
+    return AF_ERR_NOT_CONFIGURED;
+}
+
+af_err af_save_image_t(const char* filename, const af_array in_)
+{
+    printf("Error: Image IO requires FreeImage. See https://github.com/arrayfire/arrayfire\n");
+    return AF_ERR_NOT_CONFIGURED;
+}
+#endif  // WITH_FREEIMAGE
diff --git a/src/api/c/imageio_helper.h b/src/api/c/imageio_helper.h
index 907571b..a37973f 100644
--- a/src/api/c/imageio_helper.h
+++ b/src/api/c/imageio_helper.h
@@ -64,12 +64,9 @@ typedef enum {
     AFFI_RGBA = 4
 } FI_CHANNELS;
 
-// Helpers
-void FreeImageErrorHandler(FREE_IMAGE_FORMAT oFif, const char* zMessage);
-
 // Error handler for FreeImage library.
 // In case this handler is invoked, it throws an af exception.
-void FreeImageErrorHandler(FREE_IMAGE_FORMAT oFif, const char* zMessage)
+static void FreeImageErrorHandler(FREE_IMAGE_FORMAT oFif, const char* zMessage)
 {
     printf("FreeImage Error Handler: %s\n", zMessage);
 }
diff --git a/src/api/cpp/imageio.cpp b/src/api/cpp/imageio.cpp
index 7a80871..00ab963 100644
--- a/src/api/cpp/imageio.cpp
+++ b/src/api/cpp/imageio.cpp
@@ -56,4 +56,16 @@ void deleteImageMem(void* ptr)
     AF_THROW(af_delete_image_memory(ptr));
 }
 
+array loadImageT(const char* filename)
+{
+    af_array out = 0;
+    AF_THROW(af_load_image_t(&out, filename));
+    return array(out);
+}
+
+void saveImageT(const char* filename, const array& in)
+{
+    AF_THROW(af_save_image_t(filename, in.get()));
+}
+
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/arrayfire.git



More information about the debian-science-commits mailing list