mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
Add webp support (#2565)
* Add BGR(A) to pixel_traits * add support for reading webp * Apply Davis' suggestions and fix formatting * Fix signed/unsigned warning * Update decoding paths * update pixel traits documentation * Add support for writing WebP images * Simplify image_saver code * WIP: add tests, PSNR is low but images look good * Add lossless compression for quality > 100 * Fix build when WebP support is disabled * Use C++ stream instead of C-style FILE * Fix indentation * Use reinterpret_cast instead of C-style cast * Improve impl::impl_save_webp signature * Remove empty line * Use switch statement and clean up code * Update Copyright and test libwebp on Linux * Fix formatting in github workflow * Fix operator== for bgr_alpha_pixel * Show where the test fails * Add libwebp to CI for the remaining Linux workflows * Use filename consistently * Improve message with wrong pixel type * Fix tests for WebP images * Prevent saving images which are too large and improve error messages * Use max dimension from WebP header directly * Update documentation, index and release notes * Update dlib/image_saver/save_webp_abstract.h Co-authored-by: Martin T. H. Sandsmark <martin.sandsmark@kde.org> Co-authored-by: Davis E. King <davis685@gmail.com>
This commit is contained in:
parent
0aa8b4cbfc
commit
a76f205bf6
17
.github/workflows/build_cpp.yml
vendored
17
.github/workflows/build_cpp.yml
vendored
@ -22,6 +22,10 @@ jobs:
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependecies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install libwebp-dev
|
||||
- name: Configure
|
||||
run: cmake ${{ github.workspace }}/dlib/test -B ${{ env.build_dir }}
|
||||
- name: Build just tests
|
||||
@ -36,9 +40,12 @@ jobs:
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install gcc 11
|
||||
- name: Install dependecies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install libwebp-dev
|
||||
- name: Install gcc 11
|
||||
run: |
|
||||
sudo apt install gcc-11 g++-11
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 110 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11
|
||||
- name: Configure
|
||||
@ -54,6 +61,10 @@ jobs:
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependecies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install libwebp-dev
|
||||
- name: Configure
|
||||
run: |
|
||||
export CC=/usr/bin/clang
|
||||
@ -70,6 +81,10 @@ jobs:
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependecies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install libwebp-dev
|
||||
- name: Install clang 13
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
|
@ -184,6 +184,8 @@ if (NOT TARGET dlib)
|
||||
"Disable this if you don't want to link against libgif" )
|
||||
set (DLIB_JPEG_SUPPORT_STR
|
||||
"Disable this if you don't want to link against libjpeg" )
|
||||
set (DLIB_WEBP_SUPPORT_STR
|
||||
"Disable this if you don't want to link against libwebp" )
|
||||
set (DLIB_LINK_WITH_SQLITE3_STR
|
||||
"Disable this if you don't want to link against sqlite3" )
|
||||
#set (DLIB_USE_FFTW_STR "Disable this if you don't want to link against fftw" )
|
||||
@ -240,10 +242,12 @@ if (NOT TARGET dlib)
|
||||
option(DLIB_USE_CUDA ${DLIB_USE_CUDA_STR} OFF)
|
||||
option(DLIB_PNG_SUPPORT ${DLIB_PNG_SUPPORT_STR} OFF)
|
||||
option(DLIB_GIF_SUPPORT ${DLIB_GIF_SUPPORT_STR} OFF)
|
||||
option(DLIB_WEBP_SUPPORT ${DLIB_WEBP_SUPPORT_STR} OFF)
|
||||
#option(DLIB_USE_FFTW ${DLIB_USE_FFTW_STR} OFF)
|
||||
option(DLIB_USE_MKL_FFT ${DLIB_USE_MKL_FFT_STR} OFF)
|
||||
else()
|
||||
option(DLIB_JPEG_SUPPORT ${DLIB_JPEG_SUPPORT_STR} ON)
|
||||
option(DLIB_WEBP_SUPPORT ${DLIB_WEBP_SUPPORT_STR} ON)
|
||||
option(DLIB_LINK_WITH_SQLITE3 ${DLIB_LINK_WITH_SQLITE3_STR} ON)
|
||||
option(DLIB_USE_BLAS ${DLIB_USE_BLAS_STR} ON)
|
||||
option(DLIB_USE_LAPACK ${DLIB_USE_LAPACK_STR} ON)
|
||||
@ -255,6 +259,7 @@ if (NOT TARGET dlib)
|
||||
option(DLIB_USE_MKL_FFT ${DLIB_USE_MKL_FFT_STR} ON)
|
||||
endif()
|
||||
toggle_preprocessor_switch(DLIB_JPEG_SUPPORT)
|
||||
toggle_preprocessor_switch(DLIB_WEBP_SUPPORT)
|
||||
toggle_preprocessor_switch(DLIB_USE_BLAS)
|
||||
toggle_preprocessor_switch(DLIB_USE_LAPACK)
|
||||
toggle_preprocessor_switch(DLIB_USE_CUDA)
|
||||
@ -555,6 +560,20 @@ if (NOT TARGET dlib)
|
||||
image_saver/save_jpeg.cpp
|
||||
)
|
||||
endif()
|
||||
if (DLIB_WEBP_SUPPORT)
|
||||
include(cmake_utils/find_libwebp.cmake)
|
||||
if (WEBP_FOUND)
|
||||
include_directories(${WEBP_INCLUDE_DIR})
|
||||
set (dlib_needed_libraries ${dlib_needed_libraries} ${WEBP_LIBRARY})
|
||||
set(source_files ${source_files}
|
||||
image_loader/webp_loader.cpp
|
||||
image_saver/save_webp.cpp
|
||||
)
|
||||
else()
|
||||
set(DLIB_WEBP_SUPPORT OFF CACHE BOOL ${DLIB_WEBP_SUPPORT_STR} FORCE )
|
||||
toggle_preprocessor_switch(DLIB_WEBP_SUPPORT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if (DLIB_USE_BLAS OR DLIB_USE_LAPACK OR DLIB_USE_MKL_FFT)
|
||||
|
34
dlib/cmake_utils/find_libwebp.cmake
Normal file
34
dlib/cmake_utils/find_libwebp.cmake
Normal file
@ -0,0 +1,34 @@
|
||||
#=============================================================================
|
||||
# Find WebP library
|
||||
# From OpenCV
|
||||
#=============================================================================
|
||||
# Find the native WebP headers and libraries.
|
||||
#
|
||||
# WEBP_INCLUDE_DIRS - where to find webp/decode.h, etc.
|
||||
# WEBP_LIBRARIES - List of libraries when using webp.
|
||||
# WEBP_FOUND - True if webp is found.
|
||||
#=============================================================================
|
||||
|
||||
# Look for the header file.
|
||||
|
||||
unset(WEBP_FOUND)
|
||||
|
||||
FIND_PATH(WEBP_INCLUDE_DIR NAMES webp/decode.h)
|
||||
|
||||
if(NOT WEBP_INCLUDE_DIR)
|
||||
unset(WEBP_FOUND)
|
||||
else()
|
||||
MARK_AS_ADVANCED(WEBP_INCLUDE_DIR)
|
||||
|
||||
# Look for the library.
|
||||
FIND_LIBRARY(WEBP_LIBRARY NAMES webp)
|
||||
MARK_AS_ADVANCED(WEBP_LIBRARY)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set WEBP_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WebP DEFAULT_MSG WEBP_LIBRARY WEBP_INCLUDE_DIR)
|
||||
|
||||
SET(WEBP_LIBRARIES ${WEBP_LIBRARY})
|
||||
SET(WEBP_INCLUDE_DIRS ${WEBP_INCLUDE_DIR})
|
||||
endif()
|
@ -20,6 +20,7 @@
|
||||
// You should also consider telling dlib to link against libjpeg, libpng, libgif, fftw, CUDA,
|
||||
// and a BLAS and LAPACK library. To do this you need to uncomment the following #defines.
|
||||
#cmakedefine DLIB_JPEG_SUPPORT
|
||||
#cmakedefine DLIB_WEBP_SUPPORT
|
||||
#cmakedefine DLIB_PNG_SUPPORT
|
||||
#cmakedefine DLIB_GIF_SUPPORT
|
||||
#cmakedefine DLIB_USE_FFTW
|
||||
|
@ -11,10 +11,12 @@
|
||||
#include "image_loader/image_loader.h"
|
||||
#include "image_loader/png_loader.h"
|
||||
#include "image_loader/jpeg_loader.h"
|
||||
#include "image_loader/webp_loader.h"
|
||||
#include "image_loader/load_image.h"
|
||||
#include "image_saver/image_saver.h"
|
||||
#include "image_saver/save_png.h"
|
||||
#include "image_saver/save_jpeg.h"
|
||||
#include "image_saver/save_webp.h"
|
||||
|
||||
#endif // DLIB_IMAGe_IO_
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "../string.h"
|
||||
#include "png_loader.h"
|
||||
#include "jpeg_loader.h"
|
||||
#include "webp_loader.h"
|
||||
#include "image_loader.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@ -25,6 +26,7 @@ namespace dlib
|
||||
PNG,
|
||||
DNG,
|
||||
GIF,
|
||||
WEBP,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
@ -34,14 +36,15 @@ namespace dlib
|
||||
if (!file)
|
||||
throw image_load_error("Unable to open file: " + file_name);
|
||||
|
||||
char buffer[9];
|
||||
file.read((char*)buffer, 8);
|
||||
buffer[8] = 0;
|
||||
char buffer[13];
|
||||
file.read((char*)buffer, 12);
|
||||
buffer[12] = 0;
|
||||
|
||||
// Determine the true image type using link:
|
||||
// http://en.wikipedia.org/wiki/List_of_file_signatures
|
||||
static const char *pngHeader = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
|
||||
|
||||
if (strcmp(buffer, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") == 0)
|
||||
if (memcmp(buffer, pngHeader, strlen(pngHeader)) == 0)
|
||||
return PNG;
|
||||
else if(buffer[0]=='\xff' && buffer[1]=='\xd8' && buffer[2]=='\xff')
|
||||
return JPG;
|
||||
@ -51,6 +54,9 @@ namespace dlib
|
||||
return DNG;
|
||||
else if(buffer[0]=='G' && buffer[1]=='I' && buffer[2] == 'F')
|
||||
return GIF;
|
||||
else if(buffer[0]=='R' && buffer[1]=='I' && buffer[2] == 'F' && buffer[3] == 'F' &&
|
||||
buffer[8]=='W' && buffer[9]=='E' && buffer[10] == 'B' && buffer[11] == 'P')
|
||||
return WEBP;
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
@ -82,6 +88,9 @@ namespace dlib
|
||||
#ifdef DLIB_JPEG_SUPPORT
|
||||
case image_file_type::JPG: load_jpeg(image, file_name); return;
|
||||
#endif
|
||||
#ifdef DLIB_WEBP_SUPPORT
|
||||
case image_file_type::WEBP: load_webp(image, file_name); return;
|
||||
#endif
|
||||
#ifdef DLIB_GIF_SUPPORT
|
||||
case image_file_type::GIF:
|
||||
{
|
||||
|
135
dlib/image_loader/webp_loader.cpp
Normal file
135
dlib/image_loader/webp_loader.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright (C) 2022 Davis E. King (davis@dlib.net), Martin Sandsmark, Adrià Arrufat
|
||||
// License: Boost Software License See LICENSE.txt for the full license.
|
||||
#ifndef DLIB_WEBP_LOADER_CPp_
|
||||
#define DLIB_WEBP_LOADER_CPp_
|
||||
|
||||
// only do anything with this file if DLIB_WEBP_SUPPORT is defined
|
||||
#ifdef DLIB_WEBP_SUPPORT
|
||||
|
||||
#include "../array2d.h"
|
||||
#include "../pixel.h"
|
||||
#include "../dir_nav.h"
|
||||
#include "webp_loader.h"
|
||||
|
||||
#include <webp/decode.h>
|
||||
#include <fstream>
|
||||
|
||||
namespace dlib
|
||||
{
|
||||
|
||||
static std::vector<unsigned char> load_contents(const std::string& filename)
|
||||
{
|
||||
std::ifstream stream(filename, std::ios::binary);
|
||||
stream.exceptions(std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);
|
||||
stream.seekg(0, std::ios_base::end);
|
||||
std::vector<unsigned char> buffer(stream.tellg());
|
||||
stream.seekg(0);
|
||||
stream.read(reinterpret_cast<char*>(buffer.data()), buffer.size());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
webp_loader::
|
||||
webp_loader(const char* filename) : height_(0), width_(0)
|
||||
{
|
||||
data_ = load_contents(filename);
|
||||
get_info();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
webp_loader::
|
||||
webp_loader(const std::string& filename) : height_(0), width_(0)
|
||||
{
|
||||
data_ = load_contents(filename);
|
||||
get_info();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
webp_loader::
|
||||
webp_loader(const dlib::file& f) : height_(0), width_(0)
|
||||
{
|
||||
data_ = load_contents(f.full_name());
|
||||
get_info();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
webp_loader::
|
||||
webp_loader(const unsigned char* imgbuffer, size_t imgbuffersize) : height_(0), width_(0)
|
||||
{
|
||||
data_.resize(imgbuffersize);
|
||||
memcpy(data_.data(), imgbuffer, imgbuffersize);
|
||||
get_info();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void webp_loader::get_info()
|
||||
{
|
||||
if (!WebPGetInfo(data_.data(), data_.size(), &width_, &height_))
|
||||
{
|
||||
throw image_load_error("webp_loader: Invalid header");
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void webp_loader::read_argb(unsigned char *out, const size_t out_size, const int out_stride) const
|
||||
{
|
||||
if (!WebPDecodeARGBInto(data_.data(), data_.size(), out, out_size, out_stride))
|
||||
{
|
||||
throw image_load_error("webp_loader: decoding failed");
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void webp_loader::read_rgba(unsigned char *out, const size_t out_size, const int out_stride) const
|
||||
{
|
||||
if (!WebPDecodeRGBAInto(data_.data(), data_.size(), out, out_size, out_stride))
|
||||
{
|
||||
throw image_load_error("webp_loader: decoding failed");
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void webp_loader::read_bgra(unsigned char *out, const size_t out_size, const int out_stride) const
|
||||
{
|
||||
if (!WebPDecodeBGRAInto(data_.data(), data_.size(), out, out_size, out_stride))
|
||||
{
|
||||
throw image_load_error("webp_loader: decoding failed");
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void webp_loader::read_rgb(unsigned char *out, const size_t out_size, const int out_stride) const
|
||||
{
|
||||
if (!WebPDecodeRGBInto(data_.data(), data_.size(), out, out_size, out_stride))
|
||||
{
|
||||
throw image_load_error("webp_loader: decoding failed");
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void webp_loader::read_bgr(unsigned char *out, const size_t out_size, const int out_stride) const
|
||||
{
|
||||
if (!WebPDecodeBGRInto(data_.data(), data_.size(), out, out_size, out_stride))
|
||||
{
|
||||
throw image_load_error("webp_loader: decoding failed");
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
#endif // DLIB_WEBP_SUPPORT
|
||||
|
||||
#endif // DLIB_WEBP_LOADER_CPp_
|
||||
|
141
dlib/image_loader/webp_loader.h
Normal file
141
dlib/image_loader/webp_loader.h
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright (C) 2022 Davis E. King (davis@dlib.net), Martin Sandsmark, Adrià Arrufat
|
||||
// License: Boost Software License See LICENSE.txt for the full license.
|
||||
#ifndef DLIB_WEBP_IMPORT
|
||||
#define DLIB_WEBP_IMPORT
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "webp_loader_abstract.h"
|
||||
#include "image_loader.h"
|
||||
#include "../pixel.h"
|
||||
#include "../dir_nav.h"
|
||||
#include "../test_for_odr_violations.h"
|
||||
|
||||
namespace dlib
|
||||
{
|
||||
|
||||
class webp_loader : noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
webp_loader(const char* filename);
|
||||
webp_loader(const std::string& filename);
|
||||
webp_loader(const dlib::file& f);
|
||||
webp_loader(const unsigned char* imgbuffer, size_t buffersize);
|
||||
|
||||
template<typename image_type>
|
||||
void get_image(image_type& image) const
|
||||
{
|
||||
#ifndef DLIB_WEBP_SUPPORT
|
||||
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
You are getting this error because you are trying to use the webp_loader
|
||||
object but you haven't defined DLIB_WEBP_SUPPORT. You must do so to use
|
||||
this object. You must also make sure you set your build environment
|
||||
to link against the libwebp library.
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
|
||||
static_assert(sizeof(image_type) == 0, "webp support not enabled.");
|
||||
#endif
|
||||
image_view<image_type> vimg(image);
|
||||
vimg.set_size(height_, width_);
|
||||
typedef typename image_traits<image_type>::pixel_type pixel_type;
|
||||
|
||||
unsigned char* output = reinterpret_cast<unsigned char*>(image_data(vimg));
|
||||
const int stride = width_step(vimg);
|
||||
const size_t output_size = stride * height_;
|
||||
|
||||
if (pixel_traits<pixel_type>::rgb_alpha)
|
||||
{
|
||||
if (pixel_traits<pixel_type>::bgr_layout)
|
||||
read_bgra(output, output_size, stride);
|
||||
else
|
||||
read_rgba(output, output_size, stride);
|
||||
return;
|
||||
}
|
||||
if (pixel_traits<pixel_type>::rgb)
|
||||
{
|
||||
if (pixel_traits<pixel_type>::bgr_layout)
|
||||
read_bgr(output, output_size, stride);
|
||||
else
|
||||
read_rgb(output, output_size, stride);
|
||||
return;
|
||||
}
|
||||
// If we end up here, we are out of our fast path, and have to do it manually
|
||||
|
||||
array2d<rgb_alpha_pixel> decoded;
|
||||
decoded.set_size(height_, width_);
|
||||
unsigned char* output_dec = reinterpret_cast<unsigned char*>(image_data(decoded));
|
||||
const int stride_dec = width_step(decoded);
|
||||
const size_t output_dec_size = stride_dec * height_;
|
||||
|
||||
read_rgba(output_dec, output_dec_size, stride_dec);
|
||||
|
||||
for (int r = 0; r < height_; r++)
|
||||
{
|
||||
for (int c = 0; c < width_; c++)
|
||||
{
|
||||
assign_pixel(vimg[r][c], decoded[r][c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void get_info();
|
||||
void read_bgra(unsigned char *out, const size_t out_size, const int out_stride) const;
|
||||
void read_bgr(unsigned char *out, const size_t out_size, const int out_stride) const;
|
||||
void read_rgba(unsigned char *out, const size_t out_size, const int out_stride) const;
|
||||
void read_rgb(unsigned char *out, const size_t out_size, const int out_stride) const;
|
||||
void read_argb(unsigned char *out, const size_t out_size, const int out_stride) const;
|
||||
|
||||
int height_;
|
||||
int width_;
|
||||
std::vector<unsigned char> data_;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
void load_webp (
|
||||
image_type& image,
|
||||
const std::string& file_name
|
||||
)
|
||||
{
|
||||
webp_loader(file_name).get_image(image);
|
||||
}
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
void load_webp (
|
||||
image_type& image,
|
||||
const unsigned char* imgbuff,
|
||||
size_t imgbuffsize
|
||||
)
|
||||
{
|
||||
webp_loader(imgbuff, imgbuffsize).get_image(image);
|
||||
}
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
void load_webp (
|
||||
image_type& image,
|
||||
const char* imgbuff,
|
||||
size_t imgbuffsize
|
||||
)
|
||||
{
|
||||
webp_loader(reinterpret_cast<const unsigned char*>(imgbuff), imgbuffsize).get_image(image);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
#ifdef NO_MAKEFILE
|
||||
#include "webp_loader.cpp"
|
||||
#endif
|
||||
|
||||
#endif // DLIB_WEBP_IMPORT
|
||||
|
||||
|
155
dlib/image_loader/webp_loader_abstract.h
Normal file
155
dlib/image_loader/webp_loader_abstract.h
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright (C) 2022 Davis E. King (davis@dlib.net), Martin Sandsmark, Adrià Arrufat
|
||||
// License: Boost Software License See LICENSE.txt for the full license.
|
||||
#undef DLIB_WEBP_IMPORT_ABSTRACT
|
||||
#ifdef DLIB_WEBP_IMPORT_ABSTRACT
|
||||
|
||||
#include "image_loader_abstract.h"
|
||||
#include "../algs.h"
|
||||
#include "../pixel.h"
|
||||
#include "../dir_nav.h"
|
||||
#include "../image_processing/generic_image.h"
|
||||
|
||||
namespace dlib
|
||||
{
|
||||
|
||||
class webp_loader : noncopyable
|
||||
{
|
||||
/*!
|
||||
WHAT THIS OBJECT REPRESENTS
|
||||
This object represents a class capable of loading WEBP image files.
|
||||
Once an instance of it is created to contain a WEBP file from
|
||||
disk you can obtain the image stored in it via get_image().
|
||||
!*/
|
||||
|
||||
public:
|
||||
|
||||
webp_loader(
|
||||
const char* filename
|
||||
);
|
||||
/*!
|
||||
ensures
|
||||
- loads the WEBP file with the given file name into this object
|
||||
throws
|
||||
- std::bad_alloc
|
||||
- image_load_error
|
||||
This exception is thrown if there is some error that prevents
|
||||
us from loading the given WEBP file.
|
||||
!*/
|
||||
|
||||
webp_loader(
|
||||
const std::string& filename
|
||||
);
|
||||
/*!
|
||||
ensures
|
||||
- loads the WEBP file with the given file name into this object
|
||||
throws
|
||||
- std::bad_alloc
|
||||
- image_load_error
|
||||
This exception is thrown if there is some error that prevents
|
||||
us from loading the given WEBP file.
|
||||
!*/
|
||||
|
||||
webp_loader(
|
||||
const dlib::file& f
|
||||
);
|
||||
/*!
|
||||
ensures
|
||||
- loads the WEBP file with the given file name into this object
|
||||
throws
|
||||
- std::bad_alloc
|
||||
- image_load_error
|
||||
This exception is thrown if there is some error that prevents
|
||||
us from loading the given WEBP file.
|
||||
!*/
|
||||
|
||||
webp_loader(
|
||||
const unsigned char* imgbuffer,
|
||||
size_t buffersize
|
||||
);
|
||||
/*!
|
||||
ensures
|
||||
- loads the WEBP from memory imgbuffer of size buffersize into this object
|
||||
throws
|
||||
- image_load_error
|
||||
This exception is thrown if there is some error that prevents
|
||||
us from loading the given WEBP buffer.
|
||||
!*/
|
||||
|
||||
~webp_loader(
|
||||
);
|
||||
/*!
|
||||
ensures
|
||||
- all resources associated with *this has been released
|
||||
!*/
|
||||
|
||||
template<
|
||||
typename image_type
|
||||
>
|
||||
void get_image(
|
||||
image_type& img
|
||||
) const;
|
||||
/*!
|
||||
requires
|
||||
- image_type == an image object that implements the interface defined in
|
||||
dlib/image_processing/generic_image.h
|
||||
ensures
|
||||
- loads the WEBP image stored in this object into img
|
||||
!*/
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
void load_webp (
|
||||
image_type& image,
|
||||
const std::string& file_name
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- image_type == an image object that implements the interface defined in
|
||||
dlib/image_processing/generic_image.h
|
||||
ensures
|
||||
- performs: webp_loader(file_name).get_image(image);
|
||||
!*/
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
void load_webp (
|
||||
image_type& image,
|
||||
const unsigned char* imgbuff,
|
||||
size_t imgbuffsize
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- image_type == an image object that implements the interface defined in
|
||||
dlib/image_processing/generic_image.h
|
||||
ensures
|
||||
- performs: webp_loader(imgbuff, imgbuffsize).get_image(image);
|
||||
!*/
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
void load_webp (
|
||||
image_type& image,
|
||||
const char* imgbuff,
|
||||
size_t imgbuffsize
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- image_type == an image object that implements the interface defined in
|
||||
dlib/image_processing/generic_image.h
|
||||
ensures
|
||||
- performs: webp_loader((unsigned char*)imgbuff, imgbuffsize).get_image(image);
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
#endif // DLIB_WEBP_IMPORT_ABSTRACT
|
||||
|
94
dlib/image_saver/save_webp.cpp
Normal file
94
dlib/image_saver/save_webp.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
// Copyright (C) 2022 Davis E. King (davis@dlib.net), Adrià Arrufat
|
||||
// License: Boost Software License See LICENSE.txt for the full license.
|
||||
#ifndef DLIB_WEBP_SAVER_CPp_
|
||||
#define DLIB_WEBP_SAVER_CPp_
|
||||
|
||||
// only do anything with this file if DLIB_WEBP_SUPPORT is defined
|
||||
#ifdef DLIB_WEBP_SUPPORT
|
||||
|
||||
#include "save_webp.h"
|
||||
#include "image_saver.h"
|
||||
#include <sstream>
|
||||
|
||||
#include <webp/encode.h>
|
||||
|
||||
namespace dlib {
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
namespace impl
|
||||
{
|
||||
void impl_save_webp (
|
||||
const std::string& filename,
|
||||
const uint8_t* data,
|
||||
const int width,
|
||||
const int height,
|
||||
const int stride,
|
||||
const float quality,
|
||||
const webp_type type
|
||||
)
|
||||
{
|
||||
if (width > WEBP_MAX_DIMENSION || height > WEBP_MAX_DIMENSION)
|
||||
throw image_save_error("Error while encoding " + filename + ". Bad picture dimensions: "
|
||||
+ std::to_string(width) + "x" + std::to_string(height)
|
||||
+ ". Maximum WebP width and height allowed is "
|
||||
+ std::to_string(WEBP_MAX_DIMENSION) + " pixels");
|
||||
|
||||
std::ofstream fout(filename, std::ios::binary);
|
||||
if (!fout.good())
|
||||
throw image_save_error("Unable to open " + filename + " for writing.");
|
||||
|
||||
uint8_t* output;
|
||||
size_t output_size = 0;
|
||||
switch (type)
|
||||
{
|
||||
case webp_type::rgb:
|
||||
if (quality > 100)
|
||||
output_size = WebPEncodeLosslessRGB(data, width, height, stride, &output);
|
||||
else
|
||||
output_size = WebPEncodeRGB(data, width, height, stride, quality, &output);
|
||||
break;
|
||||
case webp_type::rgba:
|
||||
if (quality > 100)
|
||||
output_size = WebPEncodeLosslessRGBA(data, width, height, stride, &output);
|
||||
else
|
||||
output_size = WebPEncodeRGBA(data, width, height, stride, quality, &output);
|
||||
break;
|
||||
case webp_type::bgr:
|
||||
if (quality > 100)
|
||||
output_size = WebPEncodeLosslessBGR(data, width, height, stride, &output);
|
||||
else
|
||||
output_size = WebPEncodeBGR(data, width, height, stride, quality, &output);
|
||||
break;
|
||||
case webp_type::bgra:
|
||||
if (quality > 100)
|
||||
output_size = WebPEncodeLosslessBGRA(data, width, height, stride, &output);
|
||||
else
|
||||
output_size = WebPEncodeBGRA(data, width, height, stride, quality, &output);
|
||||
break;
|
||||
default:
|
||||
throw image_save_error("Invalid WebP color type");
|
||||
}
|
||||
|
||||
if (output_size > 0)
|
||||
{
|
||||
fout.write(reinterpret_cast<char*>(output), output_size);
|
||||
if (!fout.good())
|
||||
throw image_save_error("Error while writing WebP image to " + filename + ".");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw image_save_error("Error while encoding WebP image to " + filename + ".");
|
||||
}
|
||||
WebPFree(output);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
#endif // DLIB_WEBP_SUPPORT
|
||||
|
||||
#endif // DLIB_WEBP_SAVER_CPp_
|
||||
|
124
dlib/image_saver/save_webp.h
Normal file
124
dlib/image_saver/save_webp.h
Normal file
@ -0,0 +1,124 @@
|
||||
// Copyright (C) 2022 Davis E. King (davis@dlib.net), Adrià Arrufat
|
||||
// License: Boost Software License See LICENSE.txt for the full license.
|
||||
#ifndef DLIB_SAVE_WEBP_Hh_
|
||||
#define DLIB_SAVE_WEBP_Hh_
|
||||
|
||||
#include "save_webp_abstract.h"
|
||||
|
||||
#include "../enable_if.h"
|
||||
#include "image_saver.h"
|
||||
#include "../matrix.h"
|
||||
#include "../array2d.h"
|
||||
#include "../pixel.h"
|
||||
#include "../image_processing/generic_image.h"
|
||||
#include <string>
|
||||
|
||||
namespace dlib
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
namespace impl
|
||||
{
|
||||
enum class webp_type
|
||||
{
|
||||
rgb,
|
||||
bgr,
|
||||
rgba,
|
||||
bgra
|
||||
};
|
||||
|
||||
void impl_save_webp (
|
||||
const std::string& filename,
|
||||
const uint8_t* data,
|
||||
const int width,
|
||||
const int height,
|
||||
const int stride,
|
||||
const float quality,
|
||||
const webp_type type
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
typename disable_if<is_matrix<image_type>>::type save_webp (
|
||||
const image_type& img_,
|
||||
const std::string& filename,
|
||||
float quality = 75
|
||||
)
|
||||
{
|
||||
#ifndef DLIB_WEBP_SUPPORT
|
||||
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
You are getting this error because you are trying to use the save_webp
|
||||
function but you haven't defined DLIB_WEBP_SUPPORT. You must do so to use
|
||||
this object. You must also make sure you set your build environment
|
||||
to link against the libwebp library.
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
|
||||
static_assert(sizeof(image_type) == 0, "webp support not enabled.");
|
||||
#endif
|
||||
const_image_view<image_type> img(img_);
|
||||
using pixel_type = typename image_traits<image_type>::pixel_type;
|
||||
|
||||
// make sure requires clause is not broken
|
||||
DLIB_CASSERT(img.size() != 0,
|
||||
"\t save_webp()"
|
||||
<< "\n\t You can't save an empty image as a WEBP."
|
||||
);
|
||||
DLIB_CASSERT(0 <= quality,
|
||||
"\t save_webp()"
|
||||
<< "\n\t Invalid quality value."
|
||||
<< "\n\t quality: " << quality
|
||||
);
|
||||
|
||||
auto data = reinterpret_cast<const uint8_t*>(image_data(img));
|
||||
const int width = img.nc();
|
||||
const int height = img.nr();
|
||||
const int stride = width_step(img);
|
||||
if (pixel_traits<pixel_type>::rgb_alpha)
|
||||
{
|
||||
if (pixel_traits<pixel_type>::bgr_layout)
|
||||
impl::impl_save_webp(filename, data, width, height, stride, quality, impl::webp_type::bgra);
|
||||
else
|
||||
impl::impl_save_webp(filename, data, width, height, stride, quality, impl::webp_type::rgba);
|
||||
}
|
||||
else if (pixel_traits<pixel_type>::rgb)
|
||||
{
|
||||
if (pixel_traits<pixel_type>::bgr_layout)
|
||||
impl::impl_save_webp(filename, data, width, height, stride, quality, impl::webp_type::bgr);
|
||||
else
|
||||
impl::impl_save_webp(filename, data, width, height, stride, quality, impl::webp_type::rgb);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is some other kind of color image so just save it as an RGB image.
|
||||
array2d<rgb_pixel> temp;
|
||||
assign_image(temp, img);
|
||||
auto data = reinterpret_cast<const uint8_t*>(image_data(temp));
|
||||
impl::impl_save_webp(filename, data, width, height, stride, quality, impl::webp_type::rgb);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename EXP
|
||||
>
|
||||
void save_webp(
|
||||
const matrix_exp<EXP>& img,
|
||||
const std::string& filename,
|
||||
float quality = 75
|
||||
)
|
||||
{
|
||||
array2d<typename EXP::type> temp;
|
||||
assign_image(temp, img);
|
||||
save_webp(temp, filename, quality);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
#endif // DLIB_WEBP_SUPPORT
|
54
dlib/image_saver/save_webp_abstract.h
Normal file
54
dlib/image_saver/save_webp_abstract.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright (C) 2022 Davis E. King (davis@dlib.net), Adrià Arrufat
|
||||
// License: Boost Software License See LICENSE.txt for the full license.
|
||||
#undef DLIB_SAVE_WEBP_ABSTRACT_Hh_
|
||||
#ifdef DLIB_SAVE_WEBP_ABSTRACT_Hh_
|
||||
|
||||
#include "../image_processing/generic_image.h"
|
||||
#include "../pixel.h"
|
||||
#include <string>
|
||||
|
||||
namespace dlib
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
void save_webp (
|
||||
const image_type& img,
|
||||
const std::string& filename,
|
||||
float quality = 75
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- image_type == an image object that implements the interface defined in
|
||||
dlib/image_processing/generic_image.h or a matrix expression
|
||||
- image.size() != 0
|
||||
- quality >= 0
|
||||
ensures
|
||||
- writes the image to the file indicated by filename in the WEBP format.
|
||||
- image[0][0] will be in the upper left corner of the image.
|
||||
- image[image.nr()-1][image.nc()-1] will be in the lower right corner of the
|
||||
image.
|
||||
- This routine can save images containing any type of pixel. However,
|
||||
save_webp() can only natively store rgb_pixel, bgr_pixel, rgb_alpha_pixel and
|
||||
bgr_alpha_pixel pixel types. All other pixel types will be converted into one
|
||||
of these types as appropriate before being saved to disk.
|
||||
- The quality value determines how lossy the compression is. Larger quality
|
||||
values result in larger output images but the images will look better. A value
|
||||
between 0 and 100 will use lossy compression, while any value larger than
|
||||
100 will perform lossless compression.
|
||||
throws
|
||||
- image_save_error
|
||||
This exception is thrown if there is an error that prevents us from saving
|
||||
the image.
|
||||
- std::bad_alloc
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
#endif // DLIB_SAVE_WEBP_ABSTRACT_Hh_
|
||||
|
68
dlib/pixel.h
68
dlib/pixel.h
@ -39,6 +39,7 @@ namespace dlib
|
||||
- bool lab
|
||||
|
||||
- bool has_alpha
|
||||
- bool bgr_layout
|
||||
|
||||
- long num
|
||||
|
||||
@ -55,6 +56,7 @@ namespace dlib
|
||||
- This type of pixel represents the RGB color space.
|
||||
- num == 3
|
||||
- has_alpha == false
|
||||
- bgr_layout == true if the channel order is BGR, and false if it's RGB
|
||||
- basic_pixel_type == unsigned char
|
||||
- min() == 0
|
||||
- max() == 255
|
||||
@ -68,6 +70,7 @@ namespace dlib
|
||||
with maximum opacity.
|
||||
- num == 4
|
||||
- has_alpha == true
|
||||
- bgr_layout == true if the channel order is BGR, and false if it's RGB
|
||||
- basic_pixel_type == unsigned char
|
||||
- min() == 0
|
||||
- max() == 255
|
||||
@ -219,6 +222,46 @@ namespace dlib
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
struct bgr_alpha_pixel
|
||||
{
|
||||
/*!
|
||||
WHAT THIS OBJECT REPRESENTS
|
||||
This is a simple struct that represents an BGR colored graphical pixel
|
||||
with an alpha channel.
|
||||
!*/
|
||||
|
||||
bgr_alpha_pixel (
|
||||
) {}
|
||||
|
||||
bgr_alpha_pixel (
|
||||
unsigned char blue_,
|
||||
unsigned char green_,
|
||||
unsigned char red_,
|
||||
unsigned char alpha_
|
||||
) : blue(blue_), green(green_), red(red_), alpha(alpha_) {}
|
||||
|
||||
unsigned char blue;
|
||||
unsigned char green;
|
||||
unsigned char red;
|
||||
unsigned char alpha;
|
||||
|
||||
bool operator == (const bgr_alpha_pixel& that) const
|
||||
{
|
||||
return this->blue == that.blue
|
||||
&& this->green == that.green
|
||||
&& this->red == that.red
|
||||
&& this->alpha == that.alpha;
|
||||
}
|
||||
|
||||
bool operator != (const bgr_alpha_pixel& that) const
|
||||
{
|
||||
return !(*this == that);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
struct hsi_pixel
|
||||
@ -474,6 +517,7 @@ namespace dlib
|
||||
struct pixel_traits<rgb_pixel>
|
||||
{
|
||||
constexpr static bool rgb = true;
|
||||
constexpr static bool bgr_layout = false;
|
||||
constexpr static bool rgb_alpha = false;
|
||||
constexpr static bool grayscale = false;
|
||||
constexpr static bool hsi = false;
|
||||
@ -492,6 +536,7 @@ namespace dlib
|
||||
struct pixel_traits<bgr_pixel>
|
||||
{
|
||||
constexpr static bool rgb = true;
|
||||
constexpr static bool bgr_layout = true;
|
||||
constexpr static bool rgb_alpha = false;
|
||||
constexpr static bool grayscale = false;
|
||||
constexpr static bool hsi = false;
|
||||
@ -510,6 +555,26 @@ namespace dlib
|
||||
struct pixel_traits<rgb_alpha_pixel>
|
||||
{
|
||||
constexpr static bool rgb = false;
|
||||
constexpr static bool bgr_layout = false;
|
||||
constexpr static bool rgb_alpha = true;
|
||||
constexpr static bool grayscale = false;
|
||||
constexpr static bool hsi = false;
|
||||
constexpr static bool lab = false;
|
||||
constexpr static long num = 4;
|
||||
typedef unsigned char basic_pixel_type;
|
||||
static basic_pixel_type min() { return 0;}
|
||||
static basic_pixel_type max() { return 255;}
|
||||
constexpr static bool is_unsigned = true;
|
||||
constexpr static bool has_alpha = true;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <>
|
||||
struct pixel_traits<bgr_alpha_pixel>
|
||||
{
|
||||
constexpr static bool rgb = false;
|
||||
constexpr static bool bgr_layout = true;
|
||||
constexpr static bool rgb_alpha = true;
|
||||
constexpr static bool grayscale = false;
|
||||
constexpr static bool hsi = false;
|
||||
@ -529,6 +594,7 @@ namespace dlib
|
||||
struct pixel_traits<hsi_pixel>
|
||||
{
|
||||
constexpr static bool rgb = false;
|
||||
constexpr static bool bgr_layout = false;
|
||||
constexpr static bool rgb_alpha = false;
|
||||
constexpr static bool grayscale = false;
|
||||
constexpr static bool hsi = true;
|
||||
@ -548,6 +614,7 @@ namespace dlib
|
||||
struct pixel_traits<lab_pixel>
|
||||
{
|
||||
constexpr static bool rgb = false;
|
||||
constexpr static bool bgr_layout = false;
|
||||
constexpr static bool rgb_alpha = false;
|
||||
constexpr static bool grayscale = false;
|
||||
constexpr static bool hsi = false;
|
||||
@ -566,6 +633,7 @@ namespace dlib
|
||||
struct grayscale_pixel_traits
|
||||
{
|
||||
constexpr static bool rgb = false;
|
||||
constexpr static bool bgr_layout = false;
|
||||
constexpr static bool rgb_alpha = false;
|
||||
constexpr static bool grayscale = true;
|
||||
constexpr static bool hsi = false;
|
||||
|
@ -2306,6 +2306,119 @@ namespace
|
||||
DLIB_TEST(image == result);
|
||||
}
|
||||
|
||||
template <typename pixel_type>
|
||||
double psnr(const matrix<pixel_type>& img1, const matrix<pixel_type>& img2)
|
||||
{
|
||||
DLIB_TEST(have_same_dimensions(img1, img2));
|
||||
double mse = 0;
|
||||
const long nk = width_step(img1) / img1.nc();
|
||||
const long data_size = img1.size() * nk;
|
||||
const bool has_alpha = nk == 4;
|
||||
auto data1 = reinterpret_cast<const uint8_t*>(image_data(img1));
|
||||
auto data2 = reinterpret_cast<const uint8_t*>(image_data(img2));
|
||||
for (long i = 0; i < data_size; i += nk)
|
||||
{
|
||||
// We are using the default WebP settings, which means 'exact' is disabled.
|
||||
// RGB values in transparent areas will be modified to improve compression.
|
||||
// As a result, we skip matching transparent pixels.
|
||||
if (has_alpha && data1[i + 3] == 0 && data2[i + 3] == 0)
|
||||
continue;
|
||||
for (long k = 0; k < nk; ++k)
|
||||
mse += std::pow(static_cast<double>(data1[i + k]) - static_cast<double>(data2[i + k]), 2);
|
||||
}
|
||||
mse /= data_size;
|
||||
return 20 * std::log10(pixel_traits<pixel_type>::max()) - 10 * std::log10(mse);
|
||||
}
|
||||
|
||||
void test_webp()
|
||||
{
|
||||
#ifdef DLIB_WEBP_SUPPORT
|
||||
print_spinner();
|
||||
matrix<rgb_pixel> rgb_img, rgb_dec;
|
||||
matrix<rgb_alpha_pixel> rgba_img, rgba_dec;
|
||||
matrix<bgr_pixel> bgr_img, bgr_dec;
|
||||
matrix<bgr_alpha_pixel> bgra_img, bgra_dec;
|
||||
// this is a matrix<rgb_alpha_pixel> of the 32x32 dlib logo
|
||||
const std::string data{
|
||||
"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"
|
||||
};
|
||||
ostringstream sout;
|
||||
istringstream sin;
|
||||
base64 base64_coder;
|
||||
compress_stream::kernel_1ea compressor;
|
||||
sin.str(data);
|
||||
base64_coder.decode(sin, sout);
|
||||
sin.clear();
|
||||
sin.str(sout.str());
|
||||
sout.clear();
|
||||
sout.str("");
|
||||
compressor.decompress(sin, sout);
|
||||
sin.clear();
|
||||
sin.str(sout.str());
|
||||
deserialize(rgba_img, sin);
|
||||
for (auto quality : {75., 101.})
|
||||
{
|
||||
save_webp(rgba_img, "test_rgba.webp", quality);
|
||||
load_webp(rgba_dec, "test_rgba.webp");
|
||||
if (quality > 100)
|
||||
DLIB_TEST(psnr(rgba_img, rgba_dec) == std::numeric_limits<double>::infinity());
|
||||
else
|
||||
DLIB_TEST(psnr(rgba_img, rgba_dec) > 30);
|
||||
|
||||
assign_image(bgra_img, rgba_img);
|
||||
save_webp(bgra_img, "test_bgra.webp", quality);
|
||||
load_webp(bgra_dec, "test_bgra.webp");
|
||||
if (quality > 100)
|
||||
DLIB_TEST(psnr(bgra_img, bgra_dec) == std::numeric_limits<double>::infinity());
|
||||
else
|
||||
DLIB_TEST(psnr(bgra_img, bgra_dec) > 30);
|
||||
|
||||
// Here we assign an image with an alpha channel to an image without an alpha channel.
|
||||
// Since we are not using the exact mode in WebP, the PSNR will be quite low, since
|
||||
// pixels in transparent areas will have different values.
|
||||
assign_image(rgb_img, rgba_img);
|
||||
save_webp(rgb_img, "test_rgb.webp", quality);
|
||||
load_webp(rgb_dec, "test_rgb.webp");
|
||||
if (quality > 100)
|
||||
DLIB_TEST(psnr(rgb_img, rgb_dec) == std::numeric_limits<double>::infinity());
|
||||
else
|
||||
DLIB_TEST(psnr(rgb_img, rgb_dec) > 15);
|
||||
|
||||
assign_image(bgr_img, rgb_img);
|
||||
save_webp(bgr_img, "test_bgr.webp", quality);
|
||||
load_webp(bgr_dec, "test_bgr.webp");
|
||||
if (quality > 100)
|
||||
DLIB_TEST(psnr(bgr_img, bgr_dec) == std::numeric_limits<double>::infinity());
|
||||
else
|
||||
DLIB_TEST(psnr(bgr_img, bgr_dec) > 15);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
class image_tester : public tester
|
||||
@ -2411,6 +2524,7 @@ namespace
|
||||
test_interpolate_bilinear();
|
||||
test_letterbox_image();
|
||||
test_draw_string();
|
||||
test_webp();
|
||||
}
|
||||
} a;
|
||||
|
||||
|
@ -68,6 +68,7 @@
|
||||
<item>rgb_pixel</item>
|
||||
<item>bgr_pixel</item>
|
||||
<item>rgb_alpha_pixel</item>
|
||||
<item>bgr_alpha_pixel</item>
|
||||
<item>hsi_pixel</item>
|
||||
<item>lab_pixel</item>
|
||||
<item>pixel_traits</item>
|
||||
@ -89,6 +90,9 @@
|
||||
<item>save_dng</item>
|
||||
<item>save_png</item>
|
||||
<item>save_jpeg</item>
|
||||
<item>webp_loader</item>
|
||||
<item>load_webp</item>
|
||||
<item>save_webp</item>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@ -853,6 +857,26 @@
|
||||
|
||||
</component>
|
||||
|
||||
<!-- ************************************************************************* -->
|
||||
|
||||
<component>
|
||||
<name>bgr_alpha_pixel</name>
|
||||
<file>dlib/pixel.h</file>
|
||||
<spec_file link="true">dlib/pixel.h</spec_file>
|
||||
<description>
|
||||
This is a simple struct that represents an BGR colored graphical pixel with an
|
||||
alpha channel.
|
||||
<p>
|
||||
The difference between this object and the <a href="#rgb_alpha_pixel">rgb_alpha_pixel</a>
|
||||
is just that this struct lays its pixels down in memory in BGR order rather
|
||||
than RGB order. You only care about this if you are doing something like
|
||||
using the <a href="#cv_image">cv_image</a> object to map an OpenCV image
|
||||
into a more object oriented form.
|
||||
</p>
|
||||
</description>
|
||||
|
||||
</component>
|
||||
|
||||
<!-- ************************************************************************* -->
|
||||
|
||||
<component>
|
||||
@ -1068,6 +1092,25 @@
|
||||
|
||||
</component>
|
||||
|
||||
<!-- ************************************************************************* -->
|
||||
|
||||
<component>
|
||||
<name>webp_loader</name>
|
||||
<file>dlib/image_io.h</file>
|
||||
<spec_file link="true">dlib/image_loader/webp_loader_abstract.h</spec_file>
|
||||
<description>
|
||||
This object loads a WebP image file into
|
||||
an <a href="containers.html#array2d">array2d</a> of <a href="dlib/pixel.h.html">pixels</a>.
|
||||
<p>
|
||||
Note that you must define DLIB_WEBP_SUPPORT if you want to use this object. You
|
||||
must also set your build environment to link to the libwebp library. However,
|
||||
if you use CMake and dlib's default CMakeLists.txt file then it will get setup
|
||||
automatically.
|
||||
</p>
|
||||
</description>
|
||||
|
||||
</component>
|
||||
|
||||
<!-- ************************************************************************* -->
|
||||
|
||||
<component>
|
||||
@ -1078,7 +1121,7 @@
|
||||
This function loads a JPEG image file into
|
||||
an <a href="containers.html#array2d">array2d</a> of <a href="dlib/pixel.h.html">pixels</a>.
|
||||
<p>
|
||||
Note that you must define DLIB_JPEG_SUPPORT if you want to use this object. You
|
||||
Note that you must define DLIB_JPEG_SUPPORT if you want to use this function. You
|
||||
must also set your build environment to link to the libjpeg library. However,
|
||||
if you use CMake and dlib's default CMakeLists.txt file then it will get setup
|
||||
automatically.
|
||||
@ -1100,6 +1143,24 @@
|
||||
|
||||
</component>
|
||||
|
||||
<!-- ************************************************************************* -->
|
||||
|
||||
<component>
|
||||
<name>load_webp</name>
|
||||
<file>dlib/image_io.h</file>
|
||||
<spec_file link="true">dlib/image_loader/image_loader_abstract.h</spec_file>
|
||||
<description>
|
||||
This function loads a WebP image file into
|
||||
an <a href="containers.html#array2d">array2d</a> of <a href="dlib/pixel.h.html">pixels</a>.
|
||||
<p>
|
||||
Note that you must define DLIB_WEBP_SUPPORT if you want to use this function. You
|
||||
must also set your build environment to link to the libwebp library. However,
|
||||
if you use CMake and dlib's default CMakeLists.txt file then it will get setup
|
||||
automatically.
|
||||
</p>
|
||||
</description>
|
||||
</component>
|
||||
|
||||
<!-- ************************************************************************* -->
|
||||
|
||||
<component>
|
||||
@ -1170,6 +1231,31 @@
|
||||
|
||||
</component>
|
||||
|
||||
<!-- ************************************************************************* -->
|
||||
|
||||
<component>
|
||||
<name>save_webp</name>
|
||||
<file>dlib/image_io.h</file>
|
||||
<spec_file link="true">dlib/image_saver/save_webp_abstract.h</spec_file>
|
||||
<description>
|
||||
This global function writes an image to disk as a WebP file.
|
||||
<p>
|
||||
Note that you must define DLIB_WEBP_SUPPORT if you want to use this function. You
|
||||
must also set your build environment to link to the libwebp library. However,
|
||||
if you use CMake and dlib's default CMakeLists.txt file then it will get setup
|
||||
automatically.
|
||||
</p>
|
||||
<p>
|
||||
This routine can save images containing any type of pixel. However, save_webp() can
|
||||
only natively store the following pixel types: <b>rgb_pixel</b>,
|
||||
<b>rgb_alpha_pixel</b>, <b>bgr_pixel</b>, and <b>bgr_alpha_pixel</b>.
|
||||
All other pixel types will be converted into one of these types as appropriate
|
||||
before being saved to disk.
|
||||
</p>
|
||||
</description>
|
||||
|
||||
</component>
|
||||
|
||||
<!-- ************************************************************************* -->
|
||||
|
||||
<component>
|
||||
@ -1219,7 +1305,7 @@
|
||||
This function loads a Portable Network Graphics (PNG) image file into
|
||||
an <a href="containers.html#array2d">array2d</a> of <a href="dlib/pixel.h.html">pixels</a>.
|
||||
<p>
|
||||
Note that you must define DLIB_PNG_SUPPORT if you want to use this object. You
|
||||
Note that you must define DLIB_PNG_SUPPORT if you want to use this function. You
|
||||
must also set your build environment to link to the libpng library. However,
|
||||
if you use CMake and dlib's default CMakeLists.txt file then it will get setup
|
||||
automatically.
|
||||
|
@ -14,6 +14,8 @@
|
||||
New Features and Improvements:
|
||||
- Added Beta distribution to dlib::rand.
|
||||
- Added directory_exists.
|
||||
- Added bgr_alpha_pixel type.
|
||||
- Added support for loading and saving WebP images.
|
||||
- Deep learning tooling:
|
||||
- Added ReOrg layer.
|
||||
- Added visitor to draw network architectures using the DOT language.
|
||||
|
@ -1529,6 +1529,7 @@
|
||||
<term file="imaging.html" name="load_png" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="load_jpeg" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="load_dng" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="load_webp" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="pixel_traits" include="dlib/pixel.h"/>
|
||||
<term file="imaging.html" name="rgb_pixel" include="dlib/pixel.h"/>
|
||||
<term file="imaging.html" name="bgr_pixel" include="dlib/pixel.h"/>
|
||||
@ -1536,12 +1537,14 @@
|
||||
<term file="imaging.html" name="toMat" include="dlib/opencv.h"/>
|
||||
<term link="imaging.html#cv_image" name="OpenCV Image"/>
|
||||
<term file="imaging.html" name="rgb_alpha_pixel" include="dlib/pixel.h"/>
|
||||
<term file="imaging.html" name="bgr_alpha_pixel" include="dlib/pixel.h"/>
|
||||
<term link="imaging.html#rgb_alpha_pixel" name="alpha"/>
|
||||
<term file="imaging.html" name="save_bmp" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="save_png" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="save_jpeg" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="load_image" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="save_dng" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="save_webp" include="dlib/image_io.h"/>
|
||||
<term file="dlib/image_transforms/spatial_filtering_abstract.h.html" name="create_gaussian_filter" include="dlib/image_transforms.h"/>
|
||||
<term name="gaussian">
|
||||
<term link="dlib/image_transforms/spatial_filtering_abstract.h.html#gaussian" name="1D Gaussian" include="dlib/image_transforms.h"/>
|
||||
@ -1569,6 +1572,7 @@
|
||||
<term file="imaging.html" name="partition_pixels" include="dlib/image_transforms.h"/>
|
||||
<term file="imaging.html" name="png_loader" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="jpeg_loader" include="dlib/image_io.h"/>
|
||||
<term file="imaging.html" name="webp_loader" include="dlib/image_io.h"/>
|
||||
|
||||
<term file="imaging.html" name="interpolate_nearest_neighbor" include="dlib/image_transforms.h"/>
|
||||
<term file="imaging.html" name="interpolate_bilinear" include="dlib/image_transforms.h"/>
|
||||
|
@ -61,7 +61,7 @@ int main(int argc, char** argv) try
|
||||
|
||||
// Find supported image files.
|
||||
const std::vector<file> files = dlib::get_files_in_directory_tree(argv[1],
|
||||
dlib::match_endings(".jpeg .jpg .png"));
|
||||
dlib::match_endings(".jpeg .jpg .png .webp"));
|
||||
|
||||
dlib::rand rnd;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user