Merge branch 'LoadImage' of https://github.com/MuLx10/mlpack into MuLx10-LoadImage
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
# - Find STB_IMAGE
|
||||
# Find the STB_IMAGE C++ library
|
||||
#
|
||||
# This module sets the following variables:
|
||||
# STB_IMAGE_FOUND - set to true if the library is found
|
||||
# STB_IMAGE_INCLUDE_DIR - list of required include directories
|
||||
|
||||
file(GLOB STB_IMAGE_SEARCH_PATHS
|
||||
${CMAKE_BINARY_DIR}/deps/stb)
|
||||
find_path(STB_IMAGE_INCLUDE_DIR
|
||||
NAMES stb_image.h stb_image_write.h
|
||||
PATHS ${STB_IMAGE_SEARCH_PATHS})
|
||||
|
||||
if(STB_IMAGE_INCLUDE_DIR)
|
||||
set(STB_IMAGE_FOUND YES)
|
||||
endif ()
|
||||
|
||||
# Checks 'REQUIRED'.
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(STB_IMAGE
|
||||
REQUIRED_VARS STB_IMAGE_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(STB_IMAGE_INCLUDE_DIR)
|
||||
@@ -13,6 +13,7 @@ option(TEST_VERBOSE "Run test cases with verbose output." OFF)
|
||||
option(BUILD_TESTS "Build tests." ON)
|
||||
option(BUILD_CLI_EXECUTABLES "Build command-line executables." ON)
|
||||
option(DOWNLOAD_ENSMALLEN "If ensmallen is not found, download it." ON)
|
||||
option(DOWNLOAD_STB_IMAGE "Download stb_image for image loading." ON)
|
||||
|
||||
# Currently Python bindings aren't known to build successfully on Windows, so
|
||||
# set BUILD_PYTHON_BINDINGS to OFF when the platform is Windows.
|
||||
@@ -75,6 +76,10 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -ftemplate-depth=1000")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
|
||||
|
||||
# To remove unused functions warnings.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function")
|
||||
endif()
|
||||
|
||||
# These support libraries are used if we need to link against something
|
||||
@@ -310,6 +315,49 @@ endif ()
|
||||
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS})
|
||||
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${ARMADILLO_LIBRARIES})
|
||||
|
||||
# Find stb_image.h and stb_image_write.h.
|
||||
find_package(StbImage)
|
||||
# Download stb_image for image loading.
|
||||
if (NOT STB_IMAGE_FOUND)
|
||||
if (DOWNLOAD_STB_IMAGE)
|
||||
set(STB_DIR "stb")
|
||||
install(DIRECTORY DESTINATION ${CMAKE_BINARY_DIR}/deps/${STB_DIR})
|
||||
file(DOWNLOAD http://mlpack.org/files/stb/stb_image.h
|
||||
"${CMAKE_BINARY_DIR}/deps/${STB_DIR}/stb_image.h"
|
||||
STATUS STB_IMAGE_DOWNLOAD_STATUS_LIST LOG STB_IMAGE_DOWNLOAD_LOG
|
||||
SHOW_PROGRESS)
|
||||
list(GET STB_IMAGE_DOWNLOAD_STATUS_LIST 0 STB_IMAGE_DOWNLOAD_STATUS)
|
||||
file(DOWNLOAD http://mlpack.org/files/stb/stb_image_write.h
|
||||
"${CMAKE_BINARY_DIR}/deps/${STB_DIR}/stb_image_write.h"
|
||||
STATUS STB_IMAGE_WRITE_DOWNLOAD_STATUS_LIST
|
||||
LOG STB_IMAGE_WRITE_DOWNLOAD_LOG
|
||||
SHOW_PROGRESS)
|
||||
list(GET STB_IMAGE_WRITE_DOWNLOAD_STATUS_LIST 0
|
||||
STB_IMAGE_WRITE_DOWNLOAD_STATUS)
|
||||
if (STB_IMAGE_DOWNLOAD_STATUS EQUAL 0 AND
|
||||
STB_IMAGE_WRITE_DOWNLOAD_STATUS EQUAL 0)
|
||||
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS}
|
||||
"${CMAKE_BINARY_DIR}/deps/${STB_DIR}")
|
||||
message(STATUS
|
||||
"Successfully downloaded stb into ${CMAKE_BINARY_DIR}/deps/${STB_DIR}/")
|
||||
# Now we have to also ensure these header files get installed.
|
||||
install(FILES ${CMAKE_BINARY_DIR}/deps/${STB_DIR}/stb_image.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(FILES ${CMAKE_BINARY_DIR}/deps/${STB_DIR}/stb_image_write.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
add_definitions(-DHAS_STB)
|
||||
else ()
|
||||
list(GET STB_IMAGE_DOWNLOAD_STATUS_LIST 1 STB_DOWNLOAD_ERROR)
|
||||
message(WARNING
|
||||
"Could not download stb! Error code ${STB_DOWNLOAD_STATUS}: ${STB_DOWNLOAD_ERROR}! Error log: ${STB_DOWNLOAD_LOG}")
|
||||
endif ()
|
||||
else ()
|
||||
message(WARNING
|
||||
"stb/stb_image.h is not installed. Image utilites will not be available!")
|
||||
endif ()
|
||||
else ()
|
||||
# Already has STB installed.
|
||||
add_definitions(-DHAS_STB)
|
||||
endif ()
|
||||
|
||||
# Find ensmallen.
|
||||
# Once ensmallen is readily available in package repos, the automatic downloader
|
||||
# here can be removed.
|
||||
|
||||
@@ -113,6 +113,7 @@ Copyright:
|
||||
Copyright 2019, Dan Timson
|
||||
Copyright 2019, Miguel Canteras <mcanteras@gmail.com>
|
||||
Copyright 2019, Bishwa Karki <karkeebishwa1@gmail.com>
|
||||
Copyright 2019, Mehul Kumar Nirala <mehulkumarnirala@gmail.com>
|
||||
Copyright 2019, Yashwant Singh Parihar <yashwantsingh.sngh@gmail.com>
|
||||
|
||||
License: BSD-3-clause
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
* Fix gcc 9 OpenMP compilation issue (#1970).
|
||||
|
||||
* Added support for loading and saving of images (#1903).
|
||||
|
||||
* Add Multiple Pole Balancing Environment (#1901, #1951).
|
||||
|
||||
* Added functionality for scaling of data (#1876); see the command-line
|
||||
@@ -633,3 +635,4 @@
|
||||
* Initial release. See any resolved tickets numbered less than #196 or
|
||||
execute this query:
|
||||
http://www.mlpack.org/trac/query?status=closed&milestone=mlpack+1.0.0
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ licensed under the Boost Software License, version 1.0. This code is found in
|
||||
src/mlpack/core/boost_backport/ and more details on the licensing are available
|
||||
there.
|
||||
|
||||
mlpack may contain some usage of the source code of stb, which is licensed
|
||||
under the MIT License and the Public Domain (www.unlicense.org). This code
|
||||
is used in src/mlpack/core/data/load_image.hpp.
|
||||
|
||||
----
|
||||
Copyright (c) 2007-2018, mlpack contributors (see COPYRIGHT.txt)
|
||||
All rights reserved.
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*!
|
||||
@file image.txt
|
||||
@author Mehul Kumar Nirala
|
||||
@brief Tutorial for how to load and save images in mlpack.
|
||||
|
||||
@page imagetutorial Image Utilities tutorial
|
||||
|
||||
@section intro_imagetut Introduction
|
||||
|
||||
Image datasets are becoming increasingly popular in deep learning.
|
||||
|
||||
mlpack's image saving/loading functionality is based on [stb/](https://github.com/nothings/stb).
|
||||
|
||||
@section toc_imagetut Table of Contents
|
||||
|
||||
This tutorial is split into the following sections:
|
||||
|
||||
- \ref intro_imagetut
|
||||
- \ref toc_imagetut
|
||||
- \ref model_api_imagetut
|
||||
- \ref imageinfo_api_imagetut
|
||||
- \ref load_api_imagetut
|
||||
- \ref save_api_imagetut
|
||||
|
||||
@section model_api_imagetut Model API
|
||||
|
||||
Image utilities supports loading and saving of images.
|
||||
|
||||
It supports filetypes "jpg", "png", "tga","bmp", "psd", "gif", "hdr", "pic", "pnm" for loading and "jpg", "png", "tga", "bmp", "hdr" for saving.
|
||||
|
||||
The datatype associated is unsigned char to support RGB values in the range 1-255. To feed data into the network typecast of `arma::Mat` may be required. Images are stored in matrix as (width * height * channels, NumberOfImages). Therefore imageMatrix.col(0) would be the first image if images are loaded in imageMatrix.
|
||||
|
||||
@section imageinfo_api_imagetut ImageInfo
|
||||
|
||||
ImageInfo class contains the metadata of the images.
|
||||
@code
|
||||
/**
|
||||
* Instantiate the ImageInfo object with the image width, height, channels.
|
||||
*
|
||||
* @param width Image width.
|
||||
* @param height Image height.
|
||||
* @param channels number of channels in the image.
|
||||
*/
|
||||
ImageInfo(const size_t width,
|
||||
const size_t height,
|
||||
const size_t channels);
|
||||
@endcode
|
||||
Other public memebers include:
|
||||
- flipVertical Flip the image vertical upon loading.
|
||||
- quality Compression of the image if saved as jpg (0-100).
|
||||
|
||||
@section load_api_imagetut Load
|
||||
|
||||
|
||||
Standalone loading of images.
|
||||
@code
|
||||
/**
|
||||
* Load the image file into the given matrix.
|
||||
*
|
||||
* @param filename Name of the image file.
|
||||
* @param matrix Matrix to load the image into.
|
||||
* @param info An object of ImageInfo class.
|
||||
* @param fatal If an error should be reported as fatal (default false).
|
||||
* @param transpose If true, transpose the matrix after loading.
|
||||
* @return Boolean value indicating success or failure of load.
|
||||
*/
|
||||
template<typename eT>
|
||||
bool Load(const std::string& filename,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal,
|
||||
const bool transpose);
|
||||
@endcode
|
||||
|
||||
Loading a test image. It also fills up the ImageInfo class object.
|
||||
@code
|
||||
data::ImageInfo info;
|
||||
data::Load("test_image.png", matrix, info, false, true);
|
||||
@endcode
|
||||
|
||||
ImageInfo requires height, width, number of channels of the image.
|
||||
|
||||
@code
|
||||
size_t height = 64, width = 64, channels = 1;
|
||||
data::ImageInfo info(width, height, channels);
|
||||
@endcode
|
||||
|
||||
More than one image can be loaded into the same matrix.
|
||||
|
||||
Loading multiple images:
|
||||
|
||||
@code
|
||||
/**
|
||||
* Load the image file into the given matrix.
|
||||
*
|
||||
* @param files A vector consisting of filenames.
|
||||
* @param matrix Matrix to save the image from.
|
||||
* @param info An object of ImageInfo class.
|
||||
* @param fatal If an error should be reported as fatal (default false).
|
||||
* @param transpose If true, transpose the matrix after loading.
|
||||
* @return Boolean value indicating success or failure of load.
|
||||
*/
|
||||
template<typename eT>
|
||||
bool Load(const std::vector<std::string>& files,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal,
|
||||
const bool transpose);
|
||||
@endcode
|
||||
|
||||
@code
|
||||
data::ImageInfo info;
|
||||
std::vector<std::string>> files{"test_image1.bmp","test_image2.bmp"};
|
||||
data::load(files, matrix, info, false, true);
|
||||
@endcode
|
||||
|
||||
@section save_api_imagetut Save
|
||||
|
||||
Save images expects a matrix of type unsigned char in the form (width * height * channels, NumberOfImages).
|
||||
Just like load it can be used to save one image or multiple images. Besides image data it also expects the shape of the image as input (width, height, channels).
|
||||
|
||||
Saving one image:
|
||||
|
||||
@code
|
||||
/**
|
||||
* Save the image file from the given matrix.
|
||||
*
|
||||
* @param filename Name of the image file.
|
||||
* @param matrix Matrix to save the image from.
|
||||
* @param info An object of ImageInfo class.
|
||||
* @param fatal If an error should be reported as fatal (default false).
|
||||
* @param transpose If true, transpose the matrix after loading.
|
||||
* @return Boolean value indicating success or failure of load.
|
||||
*/
|
||||
template<typename eT>
|
||||
bool Save(const std::string& filename,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal,
|
||||
const bool transpose);
|
||||
@endcode
|
||||
|
||||
@code
|
||||
data::ImageInfo info;
|
||||
info.width = info.height = 25;
|
||||
info.channels = 3;
|
||||
info.quality = 90;
|
||||
data::Save("test_image.bmp", matrix, info, false, true);
|
||||
@endcode
|
||||
|
||||
If the matrix contains more than one image, only the first one is saved.
|
||||
|
||||
Saving multiple images:
|
||||
|
||||
@code
|
||||
/**
|
||||
* Save the image file from the given matrix.
|
||||
*
|
||||
* @param files A vector consisting of filenames.
|
||||
* @param matrix Matrix to save the image from.
|
||||
* @param info An object of ImageInfo class.
|
||||
* @param fatal If an error should be reported as fatal (default false).
|
||||
* @param transpose If true, transpose the matrix after loading.
|
||||
* @return Boolean value indicating success or failure of load.
|
||||
*/
|
||||
template<typename eT>
|
||||
bool Save(const std::vector<std::string>& files,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal,
|
||||
const bool transpose);
|
||||
@endcode
|
||||
|
||||
@code
|
||||
data::ImageInfo info;
|
||||
info.width = info.height = 25;
|
||||
info.channels = 3;
|
||||
info.quality = 90;
|
||||
std::vector<std::string>> files{"test_image1.bmp", "test_image2.bmp"};
|
||||
data::Save(files, matrix, info, false, true);
|
||||
@endcode
|
||||
|
||||
Multiple images are saved according to the vector of filenames specified.
|
||||
|
||||
*/
|
||||
@@ -10,6 +10,7 @@ set(SOURCES
|
||||
load_csv.hpp
|
||||
load_csv.cpp
|
||||
load.hpp
|
||||
load_image_impl.hpp
|
||||
load_model_impl.hpp
|
||||
load_vec_impl.hpp
|
||||
load_impl.hpp
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @file image_info.hpp
|
||||
* @author Mehul Kumar Nirala
|
||||
*
|
||||
* An image information holder.
|
||||
*
|
||||
* mlpack is free software; you may redistribute it and/or modify it under the
|
||||
* terms of the 3-clause BSD license. You should have received a copy of the
|
||||
* 3-clause BSD license along with mlpack. If not, see
|
||||
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
|
||||
*/
|
||||
|
||||
#ifndef MLPACK_CORE_DATA_IMAGE_INFO_HPP
|
||||
#define MLPACK_CORE_DATA_IMAGE_INFO_HPP
|
||||
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "extension.hpp"
|
||||
|
||||
#define STB_IMAGE_STATIC
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
#define STB_IMAGE_WRITE_STATIC
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb_image_write.h>
|
||||
|
||||
namespace mlpack {
|
||||
namespace data {
|
||||
|
||||
#ifdef HAS_STB // Compile this only if stb is present.
|
||||
|
||||
/**
|
||||
* Checks if the given image filename is supported.
|
||||
*
|
||||
* @param filename Name of the image file.
|
||||
* @return Boolean value indicating success if it is an image.
|
||||
*/
|
||||
inline bool ImageFormatSupported(const std::string& fileName,
|
||||
const bool save = false);
|
||||
|
||||
/**
|
||||
* Implements meta-data of images required by data::Load and
|
||||
* data::Save for loading and saving images into arma::Mat.
|
||||
*/
|
||||
class ImageInfo
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Instantiate the ImageInfo object with the given image width, height,
|
||||
* number of channels and quality parameter.
|
||||
*
|
||||
* @param width Image width.
|
||||
* @param height Image height.
|
||||
* @param channels Number of channels in the image.
|
||||
* @param quality Compression of the image if saved as jpg (0 - 100).
|
||||
*/
|
||||
ImageInfo(const size_t width = 0,
|
||||
const size_t height = 0,
|
||||
const size_t channels = 3,
|
||||
const size_t quality = 90);
|
||||
|
||||
//! Get the image width.
|
||||
const size_t& Width() const { return width; }
|
||||
//! Modify the image width.
|
||||
size_t& Width() { return width; }
|
||||
//! Get the image height.
|
||||
|
||||
const size_t& Height() const { return height; }
|
||||
//! Modify the image height.
|
||||
size_t& Height() { return height; }
|
||||
|
||||
//! Get the image channels.
|
||||
const size_t& Channels() const { return channels; }
|
||||
//! Modify the image channels.
|
||||
size_t& Channels() { return channels; }
|
||||
|
||||
//! Get the image quality.
|
||||
const size_t& Quality() const { return quality; }
|
||||
//! Modify the image quality.
|
||||
size_t& Quality() { return quality; }
|
||||
|
||||
private:
|
||||
// To store the image width.
|
||||
size_t width;
|
||||
|
||||
// To store the image height.
|
||||
size_t height;
|
||||
|
||||
// To store the number of channels in the image.
|
||||
size_t channels;
|
||||
|
||||
// Compression of the image if saved as jpg (0 - 100).
|
||||
size_t quality;
|
||||
};
|
||||
#else
|
||||
class ImageInfo { };
|
||||
|
||||
#endif // HAS_STB.
|
||||
|
||||
} // namespace data
|
||||
} // namespace mlpack
|
||||
|
||||
// Include implementation of Image.
|
||||
#include "image_info_impl.hpp"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @file image_info_impl.hpp
|
||||
* @author Mehul Kumar Nirala
|
||||
*
|
||||
* An image information holder implementation.
|
||||
*
|
||||
* mlpack is free software; you may redistribute it and/or modify it under the
|
||||
* terms of the 3-clause BSD license. You should have received a copy of the
|
||||
* 3-clause BSD license along with mlpack. If not, see
|
||||
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
|
||||
*/
|
||||
|
||||
#ifndef MLPACK_CORE_DATA_IMAGE_INFO_IMPL_HPP
|
||||
#define MLPACK_CORE_DATA_IMAGE_INFO_IMPL_HPP
|
||||
|
||||
#ifdef HAS_STB // Compile this only if stb is present.
|
||||
|
||||
// In case it hasn't been included yet.
|
||||
#include "image_info.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace data {
|
||||
|
||||
static const std::vector<std::string> loadFileTypes({"jpg", "png", "tga",
|
||||
"bmp", "psd", "gif", "hdr", "pic", "pnm", "jpeg"});
|
||||
|
||||
static const std::vector<std::string> saveFileTypes({"jpg", "png", "tga",
|
||||
"bmp", "hdr"});
|
||||
|
||||
inline bool ImageFormatSupported(const std::string& fileName, const bool save)
|
||||
{
|
||||
if (save)
|
||||
{
|
||||
// Iterate over all supported file types that can be saved.
|
||||
for (auto extension : saveFileTypes)
|
||||
{
|
||||
if (extension == Extension(fileName))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Iterate over all supported file types that can be loaded.
|
||||
for (auto extension : loadFileTypes)
|
||||
{
|
||||
if (extension == Extension(fileName))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline ImageInfo::ImageInfo(const size_t width,
|
||||
const size_t height,
|
||||
const size_t channels,
|
||||
const size_t quality) :
|
||||
width(width),
|
||||
height(height),
|
||||
channels(channels),
|
||||
quality(quality)
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
} // namespace data
|
||||
} // namespace mlpack
|
||||
|
||||
#endif // HAS_STB.
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "format.hpp"
|
||||
#include "dataset_mapper.hpp"
|
||||
#include "image_info.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace data /** Functions to load and save matrices and models. */ {
|
||||
@@ -287,6 +288,47 @@ bool Load(const std::string& filename,
|
||||
const bool fatal = false,
|
||||
format f = format::autodetect);
|
||||
|
||||
/**
|
||||
* Image load/save interfaces.
|
||||
*/
|
||||
#ifdef HAS_STB
|
||||
|
||||
/**
|
||||
* Load the image file into the given matrix.
|
||||
*
|
||||
* @param filename Name of the image file.
|
||||
* @param matrix Matrix to load the image into.
|
||||
* @param info An object of ImageInfo class.
|
||||
* @param fatal If an error should be reported as fatal (default false).
|
||||
* @param transpose If true, transpose the matrix after loading.
|
||||
* @return Boolean value indicating success or failure of load.
|
||||
*/
|
||||
template<typename eT>
|
||||
bool Load(const std::string& filename,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal = false,
|
||||
const bool transpose = true);
|
||||
|
||||
/**
|
||||
* Load the image file into the given matrix.
|
||||
*
|
||||
* @param files A vector consisting of filenames.
|
||||
* @param matrix Matrix to save the image from.
|
||||
* @param info An object of ImageInfo class.
|
||||
* @param fatal If an error should be reported as fatal (default false).
|
||||
* @param transpose If true, transpose the matrix after loading.
|
||||
* @return Boolean value indicating success or failure of load.
|
||||
*/
|
||||
template<typename eT>
|
||||
bool Load(const std::vector<std::string>& files,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal = false,
|
||||
const bool transpose = true);
|
||||
|
||||
#endif // HAS_STB.
|
||||
|
||||
} // namespace data
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -294,5 +336,7 @@ bool Load(const std::string& filename,
|
||||
#include "load_model_impl.hpp"
|
||||
// Include implementation of Load() for vectors.
|
||||
#include "load_vec_impl.hpp"
|
||||
// Include implementation of Load() for images.
|
||||
#include "load_image_impl.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @file load_image_impl.hpp
|
||||
* @author Mehul Kumar Nirala
|
||||
*
|
||||
* An image loading utility implementation.
|
||||
*
|
||||
* mlpack is free software; you may redistribute it and/or modify it under the
|
||||
* terms of the 3-clause BSD license. You should have received a copy of the
|
||||
* 3-clause BSD license along with mlpack. If not, see
|
||||
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
|
||||
*/
|
||||
|
||||
#ifndef MLPACK_CORE_DATA_LOAD_IMAGE_IMPL_HPP
|
||||
#define MLPACK_CORE_DATA_LOAD_IMAGE_IMPL_HPP
|
||||
|
||||
|
||||
// In case it hasn't been included yet.
|
||||
#include "load.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace data {
|
||||
|
||||
#ifdef HAS_STB // Compile this only if stb is present.
|
||||
|
||||
// Image loading API.
|
||||
template<typename eT>
|
||||
bool Load(const std::string& filename,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal,
|
||||
const bool transpose)
|
||||
{
|
||||
Timer::Start("loading_image");
|
||||
unsigned char* image;
|
||||
|
||||
if (!ImageFormatSupported(filename))
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "File type " << Extension(filename) << " not supported.\n";
|
||||
oss << "Currently it supports ";
|
||||
for (auto extension : loadFileTypes)
|
||||
oss << " " << extension;
|
||||
oss << std::endl;
|
||||
throw std::runtime_error(oss.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
stbi_set_flip_vertically_on_load(transpose);
|
||||
|
||||
// Temporary variables needed as stb_image.h supports int parameters.
|
||||
int tempWidth, tempHeight, tempChannels;
|
||||
|
||||
// For grayscale images.
|
||||
if (info.Channels() == 1)
|
||||
{
|
||||
image = stbi_load(filename.c_str(), &tempWidth, &tempHeight, &tempChannels,
|
||||
STBI_grey);
|
||||
}
|
||||
else
|
||||
{
|
||||
image = stbi_load(filename.c_str(), &tempWidth, &tempHeight, &tempChannels,
|
||||
STBI_rgb);
|
||||
}
|
||||
|
||||
if (tempWidth <= 0 || tempHeight <= 0)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Image '" << filename << "' not found." << std::endl;
|
||||
free(image);
|
||||
throw std::runtime_error(oss.str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
info.Width() = tempWidth;
|
||||
info.Height() = tempHeight;
|
||||
info.Channels() = tempChannels;
|
||||
|
||||
// Copy image into armadillo Mat.
|
||||
matrix = arma::Mat<unsigned char>(image, info.Width() * info.Height() *
|
||||
info.Channels(), 1, true, true);
|
||||
|
||||
// Free the image pointer.
|
||||
free(image);
|
||||
Timer::Stop("loading_image");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Image loading API for multiple files.
|
||||
template<typename eT>
|
||||
bool Load(const std::vector<std::string>& files,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal,
|
||||
const bool transpose)
|
||||
{
|
||||
if (files.size() == 0)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Files vector is empty." << std::endl;
|
||||
|
||||
throw std::runtime_error(oss.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
arma::Mat<unsigned char> img;
|
||||
bool status = Load(files[0], img, info, fatal, transpose);
|
||||
|
||||
// Decide matrix dimension using the image height and width.
|
||||
matrix.set_size(info.Width() * info.Height() * info.Channels(), files.size());
|
||||
matrix.col(0) = img;
|
||||
|
||||
for (size_t i = 1; i < files.size() ; i++)
|
||||
{
|
||||
arma::Mat<unsigned char> colImg(matrix.colptr(i), matrix.n_rows, 1,
|
||||
false, true);
|
||||
status &= Load(files[i], colImg, info, fatal, transpose);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
#else // No STB.
|
||||
template<typename eT>
|
||||
bool Load(const std::string& filename,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal = false,
|
||||
const bool transpose = true)
|
||||
{
|
||||
throw std::runtime_error("Load(): HAS_STB is not defined, "
|
||||
"so STB is not available and images cannot be loaded!");
|
||||
}
|
||||
|
||||
template<typename eT>
|
||||
bool Load(const std::vector<std::string>& files,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal = false,
|
||||
const bool transpose = true)
|
||||
{
|
||||
throw std::runtime_error("Load(): HAS_STB is not defined, "
|
||||
"so STB is not available and images cannot be loaded!");
|
||||
}
|
||||
#endif // HAS_STB.
|
||||
|
||||
} // namespace data
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "format.hpp"
|
||||
#include "image_info.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace data /** Functions to load and save matrices. */ {
|
||||
@@ -90,6 +91,44 @@ bool Save(const std::string& filename,
|
||||
const bool fatal = false,
|
||||
format f = format::autodetect);
|
||||
|
||||
#ifdef HAS_STB
|
||||
|
||||
/**
|
||||
* Save the image file from the given matrix.
|
||||
*
|
||||
* @param filename Name of the image file.
|
||||
* @param matrix Matrix to save the image from.
|
||||
* @param info An object of ImageInfo class.
|
||||
* @param fatal If an error should be reported as fatal (default false).
|
||||
* @param transpose If true, transpose the matrix after loading.
|
||||
* @return Boolean value indicating success or failure of load.
|
||||
*/
|
||||
template<typename eT>
|
||||
bool Save(const std::string& filename,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal = false,
|
||||
const bool transpose = true);
|
||||
|
||||
/**
|
||||
* Save the image file from the given matrix.
|
||||
*
|
||||
* @param files A vector consisting of filenames.
|
||||
* @param matrix Matrix to save the image from.
|
||||
* @param info An object of ImageInfo class.
|
||||
* @param fatal If an error should be reported as fatal (default false).
|
||||
* @param transpose If true, transpose the matrix after loading.
|
||||
* @return Boolean value indicating success or failure of load.
|
||||
*/
|
||||
template<typename eT>
|
||||
bool Save(const std::vector<std::string>& files,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal = false,
|
||||
const bool transpose = true);
|
||||
|
||||
#endif // HAS_STB.
|
||||
|
||||
} // namespace data
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
@@ -283,6 +283,147 @@ bool Save(const std::string& filename,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_STB
|
||||
// Image saving API.
|
||||
template<typename eT>
|
||||
bool Save(const std::string& filename,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal,
|
||||
const bool transpose)
|
||||
{
|
||||
Timer::Start("saving_image");
|
||||
// We transpose by default. So, un-transpose if necessary.
|
||||
if (!transpose)
|
||||
matrix = arma::trans(matrix);
|
||||
|
||||
int tempWidth, tempHeight, tempChannels, tempQuality;
|
||||
|
||||
tempWidth = info.Width();
|
||||
tempHeight = info.Height();
|
||||
tempChannels = info.Channels();
|
||||
tempQuality = info.Quality();
|
||||
|
||||
if (!ImageFormatSupported(filename, true))
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "File type " << Extension(filename) << " not supported.\n";
|
||||
oss << "Currently it supports ";
|
||||
for (auto extension : saveFileTypes)
|
||||
oss << ", " << extension;
|
||||
oss << std::endl;
|
||||
throw std::runtime_error(oss.str());
|
||||
return false;
|
||||
}
|
||||
if (matrix.n_cols > 1)
|
||||
{
|
||||
std::cout << "Input Matrix contains more than 1 image." << std::endl;
|
||||
std::cout << "Only the firstimage will be saved!" << std::endl;
|
||||
}
|
||||
stbi_flip_vertically_on_write(transpose);
|
||||
|
||||
bool status = false;
|
||||
try
|
||||
{
|
||||
unsigned char* image = matrix.memptr();
|
||||
|
||||
if ("png" == Extension(filename))
|
||||
{
|
||||
status = stbi_write_png(filename.c_str(), tempWidth, tempHeight,
|
||||
tempChannels, image, tempWidth * tempChannels);
|
||||
}
|
||||
else if ("bmp" == Extension(filename))
|
||||
{
|
||||
status = stbi_write_bmp(filename.c_str(), tempWidth, tempHeight,
|
||||
tempChannels, image);
|
||||
}
|
||||
else if ("tga" == Extension(filename))
|
||||
{
|
||||
status = stbi_write_tga(filename.c_str(), tempWidth, tempHeight,
|
||||
tempChannels, image);
|
||||
}
|
||||
else if ("hdr" == Extension(filename))
|
||||
{
|
||||
status = stbi_write_hdr(filename.c_str(), tempWidth, tempHeight,
|
||||
tempChannels, reinterpret_cast<float*>(image));
|
||||
}
|
||||
else if ("jpg" == Extension(filename))
|
||||
{
|
||||
status = stbi_write_jpg(filename.c_str(), tempWidth, tempHeight,
|
||||
tempChannels, image, tempQuality);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
Timer::Stop("saving_image");
|
||||
if (fatal)
|
||||
Log::Fatal << e.what() << std::endl;
|
||||
Log::Warn << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
Timer::Stop("saving_image");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Image saving API for multiple files.
|
||||
template<typename eT>
|
||||
bool Save(const std::vector<std::string>& files,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal,
|
||||
const bool transpose)
|
||||
{
|
||||
if (files.size() == 0)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Files vector is empty." << std::endl;
|
||||
|
||||
throw std::runtime_error(oss.str());
|
||||
return false;
|
||||
}
|
||||
// We transpose by default. So, un-transpose if necessary.
|
||||
if (!transpose)
|
||||
matrix = arma::trans(matrix);
|
||||
|
||||
arma::Mat<unsigned char> img;
|
||||
bool status = Save(files[0], img, info, fatal, transpose);
|
||||
|
||||
// Decide matrix dimension using the image height and width.
|
||||
matrix.set_size(info.Width() * info.Height() * info.Channels(), files.size());
|
||||
matrix.col(0) = img;
|
||||
|
||||
for (size_t i = 1; i < files.size() ; i++)
|
||||
{
|
||||
arma::Mat<unsigned char> colImg(matrix.colptr(i), matrix.n_rows, 1,
|
||||
false, true);
|
||||
status &= Save(files[i], colImg, info, fatal, transpose);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
#else
|
||||
template<typename eT>
|
||||
bool Save(const std::string& filename,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal = false,
|
||||
const bool transpose = true)
|
||||
{
|
||||
throw std::runtime_error("Save(): HAS_STB is not defined, "
|
||||
"so STB is not available and images cannot be saved!");
|
||||
}
|
||||
|
||||
template<typename eT>
|
||||
bool Save(const std::vector<std::string>& files,
|
||||
arma::Mat<eT>& matrix,
|
||||
ImageInfo& info,
|
||||
const bool fatal = false,
|
||||
const bool transpose = true)
|
||||
{
|
||||
throw std::runtime_error("Save(): HAS_STB is not defined, "
|
||||
"so STB is not available and images cannot be saved!");
|
||||
}
|
||||
#endif // HAS_STB.
|
||||
|
||||
} // namespace data
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ add_executable(mlpack_test
|
||||
hoeffding_tree_test.cpp
|
||||
hpt_test.cpp
|
||||
hyperplane_test.cpp
|
||||
image_load_test.cpp
|
||||
imputation_test.cpp
|
||||
init_rules_test.cpp
|
||||
kde_test.cpp
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @file image_load_test.cpp
|
||||
* @author Mehul Kumar Nirala
|
||||
*
|
||||
* Tests for loading and saving images.
|
||||
*
|
||||
* mlpack is free software; you may redistribute it and/or modify it under the
|
||||
* terms of the 3-clause BSD license. You should have received a copy of the
|
||||
* 3-clause BSD license along with mlpack. If not, see
|
||||
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
|
||||
*/
|
||||
|
||||
#include <mlpack/core.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace mlpack;
|
||||
using namespace mlpack::data;
|
||||
using namespace std;
|
||||
|
||||
#ifdef HAS_STB // Compile this only if stb is present.
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(ImageLoadTest);
|
||||
|
||||
/**
|
||||
* Test if an image with an unsupported extension throws an expected
|
||||
* exception.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(LoadInvalidExtensionFile)
|
||||
{
|
||||
arma::Mat<unsigned char> matrix;
|
||||
data::ImageInfo info;
|
||||
BOOST_REQUIRE_THROW(data::Load("invalidExtendion.p4ng", matrix, info,
|
||||
false, true), std::runtime_error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the image is loaded correctly into the matrix using the API.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(LoadImageAPITest)
|
||||
{
|
||||
arma::Mat<unsigned char> matrix;
|
||||
data::ImageInfo info;
|
||||
BOOST_REQUIRE(data::Load("test_image.png", matrix, info, false,
|
||||
true) == true);
|
||||
BOOST_REQUIRE_EQUAL(matrix.n_rows, 50 * 50 * 3); // width * height * channels.
|
||||
BOOST_REQUIRE_EQUAL(matrix.n_cols, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the image is saved correctly using API.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(SaveImageAPITest)
|
||||
{
|
||||
data::ImageInfo info(5, 5, 3, 90);
|
||||
|
||||
arma::Mat<unsigned char> im1;
|
||||
size_t dimension = info.Width() * info.Height() * info.Channels();
|
||||
im1 = arma::randi<arma::Mat<unsigned char>>(dimension, 1);
|
||||
BOOST_REQUIRE(data::Save("APITest.bmp", im1, info, false, true) == true);
|
||||
|
||||
arma::Mat<unsigned char> im2;
|
||||
BOOST_REQUIRE(data::Load("APITest.bmp", im2, info, false, true) == true);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(im1.n_cols, im2.n_cols);
|
||||
BOOST_REQUIRE_EQUAL(im1.n_rows, im2.n_rows);
|
||||
for (size_t i = 10; i < im1.n_elem; ++i)
|
||||
BOOST_REQUIRE_EQUAL(im1[i], im2[i]);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
|
||||
#endif // HAS_STB.
|
||||
Reference in New Issue
Block a user