init - 初始化项目
This commit is contained in:
174
modules/imgcodecs/CMakeLists.txt
Normal file
174
modules/imgcodecs/CMakeLists.txt
Normal file
@@ -0,0 +1,174 @@
|
||||
set(the_description "Image I/O")
|
||||
ocv_add_module(imgcodecs opencv_imgproc WRAP java objc python)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# CMake file for imgcodecs. See root CMakeLists.txt
|
||||
# Some parts taken from version of Hartmut Seichter, HIT Lab NZ.
|
||||
# Jose Luis Blanco, 2008
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
ocv_clear_vars(GRFMT_LIBS)
|
||||
|
||||
if(HAVE_WINRT_CX AND NOT WINRT)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /ZW")
|
||||
endif()
|
||||
|
||||
if(HAVE_JPEG)
|
||||
ocv_include_directories(${JPEG_INCLUDE_DIR} ${${JPEG_LIBRARY}_BINARY_DIR})
|
||||
list(APPEND GRFMT_LIBS ${JPEG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_WEBP)
|
||||
add_definitions(-DHAVE_WEBP)
|
||||
ocv_include_directories(${WEBP_INCLUDE_DIR})
|
||||
list(APPEND GRFMT_LIBS ${WEBP_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_PNG)
|
||||
add_definitions(${PNG_DEFINITIONS})
|
||||
ocv_include_directories(${PNG_INCLUDE_DIR})
|
||||
list(APPEND GRFMT_LIBS ${PNG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_GDCM)
|
||||
ocv_include_directories(${GDCM_INCLUDE_DIRS})
|
||||
list(APPEND GRFMT_LIBS ${GDCM_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_TIFF)
|
||||
ocv_include_directories(${TIFF_INCLUDE_DIR})
|
||||
list(APPEND GRFMT_LIBS ${TIFF_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_OPENJPEG)
|
||||
ocv_include_directories(${OPENJPEG_INCLUDE_DIRS})
|
||||
list(APPEND GRFMT_LIBS ${OPENJPEG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_JASPER)
|
||||
ocv_include_directories(${JASPER_INCLUDE_DIR})
|
||||
list(APPEND GRFMT_LIBS ${JASPER_LIBRARIES})
|
||||
if(OPENCV_IO_FORCE_JASPER)
|
||||
add_definitions(-DOPENCV_IMGCODECS_FORCE_JASPER=1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_OPENEXR)
|
||||
include_directories(SYSTEM ${OPENEXR_INCLUDE_PATHS})
|
||||
list(APPEND GRFMT_LIBS ${OPENEXR_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_PNG OR HAVE_TIFF OR HAVE_OPENEXR)
|
||||
ocv_include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
list(APPEND GRFMT_LIBS ${ZLIB_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_GDAL)
|
||||
include_directories(SYSTEM ${GDAL_INCLUDE_DIR})
|
||||
list(APPEND GRFMT_LIBS ${GDAL_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(HAVE_IMGCODEC_HDR)
|
||||
add_definitions(-DHAVE_IMGCODEC_HDR)
|
||||
endif()
|
||||
|
||||
if(HAVE_IMGCODEC_SUNRASTER)
|
||||
add_definitions(-DHAVE_IMGCODEC_SUNRASTER)
|
||||
endif()
|
||||
|
||||
if(HAVE_IMGCODEC_PXM)
|
||||
add_definitions(-DHAVE_IMGCODEC_PXM)
|
||||
endif()
|
||||
|
||||
if (HAVE_IMGCODEC_PFM)
|
||||
add_definitions(-DHAVE_IMGCODEC_PFM)
|
||||
endif()
|
||||
|
||||
file(GLOB grfmt_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/grfmt*.hpp)
|
||||
file(GLOB grfmt_srcs ${CMAKE_CURRENT_LIST_DIR}/src/grfmt*.cpp)
|
||||
|
||||
list(APPEND grfmt_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/bitstrm.hpp)
|
||||
list(APPEND grfmt_srcs ${CMAKE_CURRENT_LIST_DIR}/src/bitstrm.cpp)
|
||||
list(APPEND grfmt_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/rgbe.hpp)
|
||||
list(APPEND grfmt_srcs ${CMAKE_CURRENT_LIST_DIR}/src/rgbe.cpp)
|
||||
list(APPEND grfmt_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/exif.hpp)
|
||||
list(APPEND grfmt_srcs ${CMAKE_CURRENT_LIST_DIR}/src/exif.cpp)
|
||||
|
||||
source_group("Src\\grfmts" FILES ${grfmt_hdrs} ${grfmt_srcs})
|
||||
|
||||
set(imgcodecs_hdrs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/precomp.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/utils.hpp
|
||||
)
|
||||
|
||||
set(imgcodecs_srcs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/loadsave.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/utils.cpp
|
||||
)
|
||||
|
||||
file(GLOB imgcodecs_ext_hdrs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.h"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/legacy/*.h"
|
||||
)
|
||||
|
||||
if(APPLE OR APPLE_FRAMEWORK)
|
||||
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/apple_conversions.h)
|
||||
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/apple_conversions.mm)
|
||||
endif()
|
||||
if(IOS)
|
||||
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/ios_conversions.mm)
|
||||
list(APPEND IMGCODECS_LIBRARIES "-framework UIKit")
|
||||
endif()
|
||||
if(APPLE AND (NOT IOS))
|
||||
list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/macosx_conversions.mm)
|
||||
list(APPEND IMGCODECS_LIBRARIES "-framework AppKit")
|
||||
endif()
|
||||
if(APPLE_FRAMEWORK)
|
||||
list(APPEND IMGCODECS_LIBRARIES "-framework Accelerate" "-framework CoreGraphics" "-framework QuartzCore")
|
||||
endif()
|
||||
|
||||
if(TRUE)
|
||||
# these variables are set by 'ocv_append_build_options(IMGCODECS ...)'
|
||||
foreach(P ${IMGCODECS_INCLUDE_DIRS})
|
||||
ocv_include_directories(${P})
|
||||
endforeach()
|
||||
|
||||
foreach(P ${IMGCODECS_LIBRARY_DIRS})
|
||||
link_directories(${P})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
source_group("Src" FILES ${imgcodecs_srcs} ${imgcodecs_hdrs})
|
||||
source_group("Include" FILES ${imgcodecs_ext_hdrs})
|
||||
ocv_set_module_sources(HEADERS ${imgcodecs_ext_hdrs} SOURCES ${imgcodecs_srcs} ${imgcodecs_hdrs} ${grfmt_srcs} ${grfmt_hdrs})
|
||||
ocv_module_include_directories()
|
||||
|
||||
ocv_create_module(${GRFMT_LIBS} ${IMGCODECS_LIBRARIES})
|
||||
|
||||
macro(ocv_imgcodecs_configure_target)
|
||||
if(APPLE)
|
||||
add_apple_compiler_options(${the_module})
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set_target_properties(${the_module} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:atlthunk.lib /NODEFAULTLIB:atlsd.lib /NODEFAULTLIB:libcmt.lib /DEBUG")
|
||||
endif()
|
||||
|
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-deprecated-declarations)
|
||||
endmacro()
|
||||
|
||||
if(NOT BUILD_opencv_world)
|
||||
ocv_imgcodecs_configure_target()
|
||||
endif()
|
||||
|
||||
ocv_add_accuracy_tests()
|
||||
if(TARGET opencv_test_imgcodecs AND HAVE_JASPER AND "$ENV{OPENCV_IO_ENABLE_JASPER}")
|
||||
ocv_target_compile_definitions(opencv_test_imgcodecs PRIVATE OPENCV_IMGCODECS_ENABLE_JASPER_TESTS=1)
|
||||
endif()
|
||||
if(TARGET opencv_test_imgcodecs AND HAVE_PNG AND NOT (PNG_VERSION VERSION_LESS "1.6.31"))
|
||||
# details: https://github.com/glennrp/libpng/commit/68cb0aaee3de6371b81a4613476d9b33e43e95b1
|
||||
ocv_target_compile_definitions(opencv_test_imgcodecs PRIVATE OPENCV_IMGCODECS_PNG_WITH_EXIF=1)
|
||||
endif()
|
||||
ocv_add_perf_tests()
|
||||
308
modules/imgcodecs/include/opencv2/imgcodecs.hpp
Normal file
308
modules/imgcodecs/include/opencv2/imgcodecs.hpp
Normal file
@@ -0,0 +1,308 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef OPENCV_IMGCODECS_HPP
|
||||
#define OPENCV_IMGCODECS_HPP
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
/**
|
||||
@defgroup imgcodecs Image file reading and writing
|
||||
@{
|
||||
@defgroup imgcodecs_c C API
|
||||
@defgroup imgcodecs_flags Flags used for image file reading and writing
|
||||
@defgroup imgcodecs_ios iOS glue
|
||||
@defgroup imgcodecs_macosx MacOS(OSX) glue
|
||||
@}
|
||||
*/
|
||||
|
||||
//////////////////////////////// image codec ////////////////////////////////
|
||||
namespace cv
|
||||
{
|
||||
|
||||
//! @addtogroup imgcodecs
|
||||
//! @{
|
||||
|
||||
//! @addtogroup imgcodecs_flags
|
||||
//! @{
|
||||
|
||||
//! Imread flags
|
||||
enum ImreadModes {
|
||||
IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). Ignore EXIF orientation.
|
||||
IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion).
|
||||
IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image.
|
||||
IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
|
||||
IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format.
|
||||
IMREAD_LOAD_GDAL = 8, //!< If set, use the gdal driver for loading the image.
|
||||
IMREAD_REDUCED_GRAYSCALE_2 = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2.
|
||||
IMREAD_REDUCED_COLOR_2 = 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.
|
||||
IMREAD_REDUCED_GRAYSCALE_4 = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4.
|
||||
IMREAD_REDUCED_COLOR_4 = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
|
||||
IMREAD_REDUCED_GRAYSCALE_8 = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
|
||||
IMREAD_REDUCED_COLOR_8 = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
|
||||
IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag.
|
||||
};
|
||||
|
||||
//! Imwrite flags
|
||||
enum ImwriteFlags {
|
||||
IMWRITE_JPEG_QUALITY = 1, //!< For JPEG, it can be a quality from 0 to 100 (the higher is the better). Default value is 95.
|
||||
IMWRITE_JPEG_PROGRESSIVE = 2, //!< Enable JPEG features, 0 or 1, default is False.
|
||||
IMWRITE_JPEG_OPTIMIZE = 3, //!< Enable JPEG features, 0 or 1, default is False.
|
||||
IMWRITE_JPEG_RST_INTERVAL = 4, //!< JPEG restart interval, 0 - 65535, default is 0 - no restart.
|
||||
IMWRITE_JPEG_LUMA_QUALITY = 5, //!< Separate luma quality level, 0 - 100, default is 0 - don't use.
|
||||
IMWRITE_JPEG_CHROMA_QUALITY = 6, //!< Separate chroma quality level, 0 - 100, default is 0 - don't use.
|
||||
IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). Default value is 1 (best speed setting).
|
||||
IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE.
|
||||
IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0.
|
||||
IMWRITE_PXM_BINARY = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1.
|
||||
IMWRITE_EXR_TYPE = (3 << 4) + 0, /* 48 */ //!< override EXR storage type (FLOAT (FP32) is default)
|
||||
IMWRITE_EXR_COMPRESSION = (3 << 4) + 1, /* 49 */ //!< override EXR compression type (ZIP_COMPRESSION = 3 is default)
|
||||
IMWRITE_WEBP_QUALITY = 64, //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used.
|
||||
IMWRITE_PAM_TUPLETYPE = 128,//!< For PAM, sets the TUPLETYPE field to the corresponding string value that is defined for the format
|
||||
IMWRITE_TIFF_RESUNIT = 256,//!< For TIFF, use to specify which DPI resolution unit to set; see libtiff documentation for valid values
|
||||
IMWRITE_TIFF_XDPI = 257,//!< For TIFF, use to specify the X direction DPI
|
||||
IMWRITE_TIFF_YDPI = 258, //!< For TIFF, use to specify the Y direction DPI
|
||||
IMWRITE_TIFF_COMPRESSION = 259, //!< For TIFF, use to specify the image compression scheme. See libtiff for integer constants corresponding to compression formats. Note, for images whose depth is CV_32F, only libtiff's SGILOG compression scheme is used. For other supported depths, the compression scheme can be specified by this flag; LZW compression is the default.
|
||||
IMWRITE_JPEG2000_COMPRESSION_X1000 = 272 //!< For JPEG2000, use to specify the target compression rate (multiplied by 1000). The value can be from 0 to 1000. Default is 1000.
|
||||
};
|
||||
|
||||
enum ImwriteEXRTypeFlags {
|
||||
/*IMWRITE_EXR_TYPE_UNIT = 0, //!< not supported */
|
||||
IMWRITE_EXR_TYPE_HALF = 1, //!< store as HALF (FP16)
|
||||
IMWRITE_EXR_TYPE_FLOAT = 2 //!< store as FP32 (default)
|
||||
};
|
||||
|
||||
enum ImwriteEXRCompressionFlags {
|
||||
IMWRITE_EXR_COMPRESSION_NO = 0, //!< no compression
|
||||
IMWRITE_EXR_COMPRESSION_RLE = 1, //!< run length encoding
|
||||
IMWRITE_EXR_COMPRESSION_ZIPS = 2, //!< zlib compression, one scan line at a time
|
||||
IMWRITE_EXR_COMPRESSION_ZIP = 3, //!< zlib compression, in blocks of 16 scan lines
|
||||
IMWRITE_EXR_COMPRESSION_PIZ = 4, //!< piz-based wavelet compression
|
||||
IMWRITE_EXR_COMPRESSION_PXR24 = 5, //!< lossy 24-bit float compression
|
||||
IMWRITE_EXR_COMPRESSION_B44 = 6, //!< lossy 4-by-4 pixel block compression, fixed compression rate
|
||||
IMWRITE_EXR_COMPRESSION_B44A = 7, //!< lossy 4-by-4 pixel block compression, flat fields are compressed more
|
||||
IMWRITE_EXR_COMPRESSION_DWAA = 8, //!< lossy DCT based compression, in blocks of 32 scanlines. More efficient for partial buffer access.
|
||||
IMWRITE_EXR_COMPRESSION_DWAB = 9, //!< lossy DCT based compression, in blocks of 256 scanlines. More efficient space wise and faster to decode full frames than DWAA_COMPRESSION.
|
||||
};
|
||||
|
||||
//! Imwrite PNG specific flags used to tune the compression algorithm.
|
||||
/** These flags will be modify the way of PNG image compression and will be passed to the underlying zlib processing stage.
|
||||
|
||||
- The effect of IMWRITE_PNG_STRATEGY_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between IMWRITE_PNG_STRATEGY_DEFAULT and IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY.
|
||||
- IMWRITE_PNG_STRATEGY_RLE is designed to be almost as fast as IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY, but give better compression for PNG image data.
|
||||
- The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately.
|
||||
- IMWRITE_PNG_STRATEGY_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications.
|
||||
*/
|
||||
enum ImwritePNGFlags {
|
||||
IMWRITE_PNG_STRATEGY_DEFAULT = 0, //!< Use this value for normal data.
|
||||
IMWRITE_PNG_STRATEGY_FILTERED = 1, //!< Use this value for data produced by a filter (or predictor).Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better.
|
||||
IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY = 2, //!< Use this value to force Huffman encoding only (no string match).
|
||||
IMWRITE_PNG_STRATEGY_RLE = 3, //!< Use this value to limit match distances to one (run-length encoding).
|
||||
IMWRITE_PNG_STRATEGY_FIXED = 4 //!< Using this value prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications.
|
||||
};
|
||||
|
||||
//! Imwrite PAM specific tupletype flags used to define the 'TUPETYPE' field of a PAM file.
|
||||
enum ImwritePAMFlags {
|
||||
IMWRITE_PAM_FORMAT_NULL = 0,
|
||||
IMWRITE_PAM_FORMAT_BLACKANDWHITE = 1,
|
||||
IMWRITE_PAM_FORMAT_GRAYSCALE = 2,
|
||||
IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA = 3,
|
||||
IMWRITE_PAM_FORMAT_RGB = 4,
|
||||
IMWRITE_PAM_FORMAT_RGB_ALPHA = 5,
|
||||
};
|
||||
|
||||
//! @} imgcodecs_flags
|
||||
|
||||
/** @brief Loads an image from a file.
|
||||
|
||||
@anchor imread
|
||||
|
||||
The function imread loads an image from the specified file and returns it. If the image cannot be
|
||||
read (because of missing file, improper permissions, unsupported or invalid format), the function
|
||||
returns an empty matrix ( Mat::data==NULL ).
|
||||
|
||||
Currently, the following file formats are supported:
|
||||
|
||||
- Windows bitmaps - \*.bmp, \*.dib (always supported)
|
||||
- JPEG files - \*.jpeg, \*.jpg, \*.jpe (see the *Note* section)
|
||||
- JPEG 2000 files - \*.jp2 (see the *Note* section)
|
||||
- Portable Network Graphics - \*.png (see the *Note* section)
|
||||
- WebP - \*.webp (see the *Note* section)
|
||||
- Portable image format - \*.pbm, \*.pgm, \*.ppm \*.pxm, \*.pnm (always supported)
|
||||
- PFM files - \*.pfm (see the *Note* section)
|
||||
- Sun rasters - \*.sr, \*.ras (always supported)
|
||||
- TIFF files - \*.tiff, \*.tif (see the *Note* section)
|
||||
- OpenEXR Image files - \*.exr (see the *Note* section)
|
||||
- Radiance HDR - \*.hdr, \*.pic (always supported)
|
||||
- Raster and Vector geospatial data supported by GDAL (see the *Note* section)
|
||||
|
||||
@note
|
||||
- The function determines the type of an image by the content, not by the file extension.
|
||||
- In the case of color images, the decoded images will have the channels stored in **B G R** order.
|
||||
- When using IMREAD_GRAYSCALE, the codec's internal grayscale conversion will be used, if available.
|
||||
Results may differ to the output of cvtColor()
|
||||
- On Microsoft Windows\* OS and MacOSX\*, the codecs shipped with an OpenCV image (libjpeg,
|
||||
libpng, libtiff, and libjasper) are used by default. So, OpenCV can always read JPEGs, PNGs,
|
||||
and TIFFs. On MacOSX, there is also an option to use native MacOSX image readers. But beware
|
||||
that currently these native image loaders give images with different pixel values because of
|
||||
the color management embedded into MacOSX.
|
||||
- On Linux\*, BSD flavors and other Unix-like open-source operating systems, OpenCV looks for
|
||||
codecs supplied with an OS image. Install the relevant packages (do not forget the development
|
||||
files, for example, "libjpeg-dev", in Debian\* and Ubuntu\*) to get the codec support or turn
|
||||
on the OPENCV_BUILD_3RDPARTY_LIBS flag in CMake.
|
||||
- In the case you set *WITH_GDAL* flag to true in CMake and @ref IMREAD_LOAD_GDAL to load the image,
|
||||
then the [GDAL](http://www.gdal.org) driver will be used in order to decode the image, supporting
|
||||
the following formats: [Raster](http://www.gdal.org/formats_list.html),
|
||||
[Vector](http://www.gdal.org/ogr_formats.html).
|
||||
- If EXIF information is embedded in the image file, the EXIF orientation will be taken into account
|
||||
and thus the image will be rotated accordingly except if the flags @ref IMREAD_IGNORE_ORIENTATION
|
||||
or @ref IMREAD_UNCHANGED are passed.
|
||||
- Use the IMREAD_UNCHANGED flag to keep the floating point values from PFM image.
|
||||
- By default number of pixels must be less than 2^30. Limit can be set using system
|
||||
variable OPENCV_IO_MAX_IMAGE_PIXELS
|
||||
|
||||
@param filename Name of file to be loaded.
|
||||
@param flags Flag that can take values of cv::ImreadModes
|
||||
*/
|
||||
CV_EXPORTS_W Mat imread( const String& filename, int flags = IMREAD_COLOR );
|
||||
|
||||
/** @brief Loads a multi-page image from a file.
|
||||
|
||||
The function imreadmulti loads a multi-page image from the specified file into a vector of Mat objects.
|
||||
@param filename Name of file to be loaded.
|
||||
@param flags Flag that can take values of cv::ImreadModes, default with cv::IMREAD_ANYCOLOR.
|
||||
@param mats A vector of Mat objects holding each page, if more than one.
|
||||
@sa cv::imread
|
||||
*/
|
||||
CV_EXPORTS_W bool imreadmulti(const String& filename, CV_OUT std::vector<Mat>& mats, int flags = IMREAD_ANYCOLOR);
|
||||
|
||||
/** @brief Saves an image to a specified file.
|
||||
|
||||
The function imwrite saves the image to the specified file. The image format is chosen based on the
|
||||
filename extension (see cv::imread for the list of extensions). In general, only 8-bit
|
||||
single-channel or 3-channel (with 'BGR' channel order) images
|
||||
can be saved using this function, with these exceptions:
|
||||
|
||||
- 16-bit unsigned (CV_16U) images can be saved in the case of PNG, JPEG 2000, and TIFF formats
|
||||
- 32-bit float (CV_32F) images can be saved in PFM, TIFF, OpenEXR, and Radiance HDR formats;
|
||||
3-channel (CV_32FC3) TIFF images will be saved using the LogLuv high dynamic range encoding
|
||||
(4 bytes per pixel)
|
||||
- PNG images with an alpha channel can be saved using this function. To do this, create
|
||||
8-bit (or 16-bit) 4-channel image BGRA, where the alpha channel goes last. Fully transparent pixels
|
||||
should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535 (see the code sample below).
|
||||
- Multiple images (vector of Mat) can be saved in TIFF format (see the code sample below).
|
||||
|
||||
If the format, depth or channel order is different, use
|
||||
Mat::convertTo and cv::cvtColor to convert it before saving. Or, use the universal FileStorage I/O
|
||||
functions to save the image to XML or YAML format.
|
||||
|
||||
The sample below shows how to create a BGRA image, how to set custom compression parameters and save it to a PNG file.
|
||||
It also demonstrates how to save multiple images in a TIFF file:
|
||||
@include snippets/imgcodecs_imwrite.cpp
|
||||
@param filename Name of the file.
|
||||
@param img (Mat or vector of Mat) Image or Images to be saved.
|
||||
@param params Format-specific parameters encoded as pairs (paramId_1, paramValue_1, paramId_2, paramValue_2, ... .) see cv::ImwriteFlags
|
||||
*/
|
||||
CV_EXPORTS_W bool imwrite( const String& filename, InputArray img,
|
||||
const std::vector<int>& params = std::vector<int>());
|
||||
|
||||
/// @overload multi-image overload for bindings
|
||||
CV_WRAP static inline
|
||||
bool imwritemulti(const String& filename, InputArrayOfArrays img,
|
||||
const std::vector<int>& params = std::vector<int>())
|
||||
{
|
||||
return imwrite(filename, img, params);
|
||||
}
|
||||
|
||||
/** @brief Reads an image from a buffer in memory.
|
||||
|
||||
The function imdecode reads an image from the specified buffer in the memory. If the buffer is too short or
|
||||
contains invalid data, the function returns an empty matrix ( Mat::data==NULL ).
|
||||
|
||||
See cv::imread for the list of supported formats and flags description.
|
||||
|
||||
@note In the case of color images, the decoded images will have the channels stored in **B G R** order.
|
||||
@param buf Input array or vector of bytes.
|
||||
@param flags The same flags as in cv::imread, see cv::ImreadModes.
|
||||
*/
|
||||
CV_EXPORTS_W Mat imdecode( InputArray buf, int flags );
|
||||
|
||||
/** @overload
|
||||
@param buf
|
||||
@param flags
|
||||
@param dst The optional output placeholder for the decoded matrix. It can save the image
|
||||
reallocations when the function is called repeatedly for images of the same size.
|
||||
*/
|
||||
CV_EXPORTS Mat imdecode( InputArray buf, int flags, Mat* dst);
|
||||
|
||||
/** @brief Encodes an image into a memory buffer.
|
||||
|
||||
The function imencode compresses the image and stores it in the memory buffer that is resized to fit the
|
||||
result. See cv::imwrite for the list of supported formats and flags description.
|
||||
|
||||
@param ext File extension that defines the output format.
|
||||
@param img Image to be written.
|
||||
@param buf Output buffer resized to fit the compressed image.
|
||||
@param params Format-specific parameters. See cv::imwrite and cv::ImwriteFlags.
|
||||
*/
|
||||
CV_EXPORTS_W bool imencode( const String& ext, InputArray img,
|
||||
CV_OUT std::vector<uchar>& buf,
|
||||
const std::vector<int>& params = std::vector<int>());
|
||||
|
||||
/** @brief Returns true if the specified image can be decoded by OpenCV
|
||||
|
||||
@param filename File name of the image
|
||||
*/
|
||||
CV_EXPORTS_W bool haveImageReader( const String& filename );
|
||||
|
||||
/** @brief Returns true if an image with the specified filename can be encoded by OpenCV
|
||||
|
||||
@param filename File name of the image
|
||||
*/
|
||||
CV_EXPORTS_W bool haveImageWriter( const String& filename );
|
||||
|
||||
|
||||
//! @} imgcodecs
|
||||
|
||||
} // cv
|
||||
|
||||
#endif //OPENCV_IMGCODECS_HPP
|
||||
48
modules/imgcodecs/include/opencv2/imgcodecs/imgcodecs.hpp
Normal file
48
modules/imgcodecs/include/opencv2/imgcodecs/imgcodecs.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifdef __OPENCV_BUILD
|
||||
#error this is a compatibility header which should not be used inside the OpenCV library
|
||||
#endif
|
||||
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
@@ -0,0 +1 @@
|
||||
#error "This header with legacy C API declarations has been removed from OpenCV. Legacy constants are available from legacy/constants_c.h file."
|
||||
59
modules/imgcodecs/include/opencv2/imgcodecs/ios.h
Normal file
59
modules/imgcodecs/include/opencv2/imgcodecs/ios.h
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Accelerate/Accelerate.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
//! @addtogroup imgcodecs_ios
|
||||
//! @{
|
||||
|
||||
CV_EXPORTS CGImageRef MatToCGImage(const cv::Mat& image) CF_RETURNS_RETAINED;
|
||||
CV_EXPORTS void CGImageToMat(const CGImageRef image, cv::Mat& m, bool alphaExist = false);
|
||||
CV_EXPORTS UIImage* MatToUIImage(const cv::Mat& image);
|
||||
CV_EXPORTS void UIImageToMat(const UIImage* image,
|
||||
cv::Mat& m, bool alphaExist = false);
|
||||
|
||||
//! @}
|
||||
@@ -0,0 +1,54 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef OPENCV_IMGCODECS_LEGACY_CONSTANTS_H
|
||||
#define OPENCV_IMGCODECS_LEGACY_CONSTANTS_H
|
||||
|
||||
/* duplicate of "ImreadModes" enumeration for better compatibility with OpenCV 3.x */
|
||||
enum
|
||||
{
|
||||
/* 8bit, color or not */
|
||||
CV_LOAD_IMAGE_UNCHANGED =-1,
|
||||
/* 8bit, gray */
|
||||
CV_LOAD_IMAGE_GRAYSCALE =0,
|
||||
/* ?, color */
|
||||
CV_LOAD_IMAGE_COLOR =1,
|
||||
/* any depth, ? */
|
||||
CV_LOAD_IMAGE_ANYDEPTH =2,
|
||||
/* ?, any color */
|
||||
CV_LOAD_IMAGE_ANYCOLOR =4,
|
||||
/* ?, no rotate */
|
||||
CV_LOAD_IMAGE_IGNORE_ORIENTATION =128
|
||||
};
|
||||
|
||||
/* duplicate of "ImwriteFlags" enumeration for better compatibility with OpenCV 3.x */
|
||||
enum
|
||||
{
|
||||
CV_IMWRITE_JPEG_QUALITY =1,
|
||||
CV_IMWRITE_JPEG_PROGRESSIVE =2,
|
||||
CV_IMWRITE_JPEG_OPTIMIZE =3,
|
||||
CV_IMWRITE_JPEG_RST_INTERVAL =4,
|
||||
CV_IMWRITE_JPEG_LUMA_QUALITY =5,
|
||||
CV_IMWRITE_JPEG_CHROMA_QUALITY =6,
|
||||
CV_IMWRITE_PNG_COMPRESSION =16,
|
||||
CV_IMWRITE_PNG_STRATEGY =17,
|
||||
CV_IMWRITE_PNG_BILEVEL =18,
|
||||
CV_IMWRITE_PNG_STRATEGY_DEFAULT =0,
|
||||
CV_IMWRITE_PNG_STRATEGY_FILTERED =1,
|
||||
CV_IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY =2,
|
||||
CV_IMWRITE_PNG_STRATEGY_RLE =3,
|
||||
CV_IMWRITE_PNG_STRATEGY_FIXED =4,
|
||||
CV_IMWRITE_PXM_BINARY =32,
|
||||
CV_IMWRITE_EXR_TYPE = 48,
|
||||
CV_IMWRITE_WEBP_QUALITY =64,
|
||||
CV_IMWRITE_PAM_TUPLETYPE = 128,
|
||||
CV_IMWRITE_PAM_FORMAT_NULL = 0,
|
||||
CV_IMWRITE_PAM_FORMAT_BLACKANDWHITE = 1,
|
||||
CV_IMWRITE_PAM_FORMAT_GRAYSCALE = 2,
|
||||
CV_IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA = 3,
|
||||
CV_IMWRITE_PAM_FORMAT_RGB = 4,
|
||||
CV_IMWRITE_PAM_FORMAT_RGB_ALPHA = 5,
|
||||
};
|
||||
|
||||
#endif // OPENCV_IMGCODECS_LEGACY_CONSTANTS_H
|
||||
20
modules/imgcodecs/include/opencv2/imgcodecs/macosx.h
Normal file
20
modules/imgcodecs/include/opencv2/imgcodecs/macosx.h
Normal file
@@ -0,0 +1,20 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#if !defined(__APPLE__) || !defined(__MACH__)
|
||||
#error This header should be used in macOS ObjC/Swift projects.
|
||||
#endif
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
//! @addtogroup imgcodecs_macosx
|
||||
//! @{
|
||||
|
||||
CV_EXPORTS CGImageRef MatToCGImage(const cv::Mat& image) CF_RETURNS_RETAINED;
|
||||
CV_EXPORTS void CGImageToMat(const CGImageRef image, cv::Mat& m, bool alphaExist = false);
|
||||
CV_EXPORTS NSImage* MatToNSImage(const cv::Mat& image);
|
||||
CV_EXPORTS void NSImageToMat(const NSImage* image, cv::Mat& m, bool alphaExist = false);
|
||||
|
||||
//! @}
|
||||
63
modules/imgcodecs/misc/java/test/ImgcodecsTest.java
Normal file
63
modules/imgcodecs/misc/java/test/ImgcodecsTest.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package org.opencv.test.imgcodecs;
|
||||
|
||||
import org.opencv.core.MatOfByte;
|
||||
import org.opencv.core.MatOfInt;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import org.opencv.test.OpenCVTestRunner;
|
||||
|
||||
public class ImgcodecsTest extends OpenCVTestCase {
|
||||
|
||||
public void testImdecode() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testImencodeStringMatListOfByte() {
|
||||
MatOfByte buff = new MatOfByte();
|
||||
assertEquals(0, buff.total());
|
||||
assertTrue( Imgcodecs.imencode(".jpg", gray127, buff) );
|
||||
assertFalse(0 == buff.total());
|
||||
}
|
||||
|
||||
public void testImencodeStringMatListOfByteListOfInteger() {
|
||||
MatOfInt params40 = new MatOfInt(Imgcodecs.IMWRITE_JPEG_QUALITY, 40);
|
||||
MatOfInt params90 = new MatOfInt(Imgcodecs.IMWRITE_JPEG_QUALITY, 90);
|
||||
/* or
|
||||
MatOfInt params = new MatOfInt();
|
||||
params.fromArray(Imgcodecs.IMWRITE_JPEG_QUALITY, 40);
|
||||
*/
|
||||
MatOfByte buff40 = new MatOfByte();
|
||||
MatOfByte buff90 = new MatOfByte();
|
||||
|
||||
assertTrue( Imgcodecs.imencode(".jpg", rgbLena, buff40, params40) );
|
||||
assertTrue( Imgcodecs.imencode(".jpg", rgbLena, buff90, params90) );
|
||||
|
||||
assertTrue(buff40.total() > 0);
|
||||
assertTrue(buff40.total() < buff90.total());
|
||||
}
|
||||
|
||||
public void testImreadString() {
|
||||
dst = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH);
|
||||
assertFalse(dst.empty());
|
||||
assertEquals(3, dst.channels());
|
||||
assertTrue(512 == dst.cols());
|
||||
assertTrue(512 == dst.rows());
|
||||
}
|
||||
|
||||
public void testImreadStringInt() {
|
||||
dst = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH, 0);
|
||||
assertFalse(dst.empty());
|
||||
assertEquals(1, dst.channels());
|
||||
assertTrue(512 == dst.cols());
|
||||
assertTrue(512 == dst.rows());
|
||||
}
|
||||
|
||||
public void testImwriteStringMat() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
public void testImwriteStringMatListOfInteger() {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
32
modules/imgcodecs/misc/objc/ios/Mat+Converters.h
Normal file
32
modules/imgcodecs/misc/objc/ios/Mat+Converters.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Mat+UIImage.h
|
||||
//
|
||||
// Created by Giles Payne on 2020/03/03.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#import "opencv2/core.hpp"
|
||||
#else
|
||||
#define CV_EXPORTS
|
||||
#endif
|
||||
|
||||
#import "Mat.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
CV_EXPORTS @interface Mat (Converters)
|
||||
|
||||
-(CGImageRef)toCGImage CF_RETURNS_RETAINED;
|
||||
-(instancetype)initWithCGImage:(CGImageRef)image;
|
||||
-(instancetype)initWithCGImage:(CGImageRef)image alphaExist:(BOOL)alphaExist;
|
||||
-(UIImage*)toUIImage;
|
||||
-(instancetype)initWithUIImage:(UIImage*)image;
|
||||
-(instancetype)initWithUIImage:(UIImage*)image alphaExist:(BOOL)alphaExist;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
44
modules/imgcodecs/misc/objc/ios/Mat+Converters.mm
Normal file
44
modules/imgcodecs/misc/objc/ios/Mat+Converters.mm
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Mat+UIImage.mm
|
||||
//
|
||||
// Created by Giles Payne on 2020/03/03.
|
||||
//
|
||||
|
||||
#import "Mat+Converters.h"
|
||||
#import <opencv2/imgcodecs/ios.h>
|
||||
|
||||
@implementation Mat (Converters)
|
||||
|
||||
-(CGImageRef)toCGImage {
|
||||
return MatToCGImage(self.nativeRef);
|
||||
}
|
||||
|
||||
-(instancetype)initWithCGImage:(CGImageRef)image {
|
||||
return [self initWithCGImage:image alphaExist:NO];
|
||||
}
|
||||
|
||||
-(instancetype)initWithCGImage:(CGImageRef)image alphaExist:(BOOL)alphaExist {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
CGImageToMat(image, self.nativeRef, (bool)alphaExist);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(UIImage*)toUIImage {
|
||||
return MatToUIImage(self.nativeRef);
|
||||
}
|
||||
|
||||
-(instancetype)initWithUIImage:(UIImage*)image {
|
||||
return [self initWithUIImage:image alphaExist:NO];
|
||||
}
|
||||
|
||||
-(instancetype)initWithUIImage:(UIImage*)image alphaExist:(BOOL)alphaExist {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
UIImageToMat(image, self.nativeRef, (bool)alphaExist);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
32
modules/imgcodecs/misc/objc/macosx/Mat+Converters.h
Normal file
32
modules/imgcodecs/misc/objc/macosx/Mat+Converters.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Mat+Converters.h
|
||||
//
|
||||
// Created by Masaya Tsuruta on 2020/10/08.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#import "opencv2/core.hpp"
|
||||
#else
|
||||
#define CV_EXPORTS
|
||||
#endif
|
||||
|
||||
#import "Mat.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
CV_EXPORTS @interface Mat (Converters)
|
||||
|
||||
-(CGImageRef)toCGImage CF_RETURNS_RETAINED;
|
||||
-(instancetype)initWithCGImage:(CGImageRef)image;
|
||||
-(instancetype)initWithCGImage:(CGImageRef)image alphaExist:(BOOL)alphaExist;
|
||||
-(NSImage*)toNSImage;
|
||||
-(instancetype)initWithNSImage:(NSImage*)image;
|
||||
-(instancetype)initWithNSImage:(NSImage*)image alphaExist:(BOOL)alphaExist;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
44
modules/imgcodecs/misc/objc/macosx/Mat+Converters.mm
Normal file
44
modules/imgcodecs/misc/objc/macosx/Mat+Converters.mm
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Mat+Converters.mm
|
||||
//
|
||||
// Created by Masaya Tsuruta on 2020/10/08.
|
||||
//
|
||||
|
||||
#import "Mat+Converters.h"
|
||||
#import <opencv2/imgcodecs/macosx.h>
|
||||
|
||||
@implementation Mat (Converters)
|
||||
|
||||
-(CGImageRef)toCGImage {
|
||||
return MatToCGImage(self.nativeRef);
|
||||
}
|
||||
|
||||
-(instancetype)initWithCGImage:(CGImageRef)image {
|
||||
return [self initWithCGImage:image alphaExist:NO];
|
||||
}
|
||||
|
||||
-(instancetype)initWithCGImage:(CGImageRef)image alphaExist:(BOOL)alphaExist {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
CGImageToMat(image, self.nativeRef, (bool)alphaExist);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(NSImage*)toNSImage {
|
||||
return MatToNSImage(self.nativeRef);
|
||||
}
|
||||
|
||||
-(instancetype)initWithNSImage:(NSImage*)image {
|
||||
return [self initWithNSImage:image alphaExist:NO];
|
||||
}
|
||||
|
||||
-(instancetype)initWithNSImage:(NSImage*)image alphaExist:(BOOL)alphaExist {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
NSImageToMat(image, self.nativeRef, (bool)alphaExist);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
50
modules/imgcodecs/misc/objc/test/ImgcodecsTest.swift
Normal file
50
modules/imgcodecs/misc/objc/test/ImgcodecsTest.swift
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// Imgcodecs.swift
|
||||
//
|
||||
// Created by Giles Payne on 2020/02/10.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import OpenCV
|
||||
|
||||
class ImgcodecsTest: OpenCVTestCase {
|
||||
|
||||
let LENA_PATH = Bundle(for: ImgcodecsTest.self).path(forResource:"lena", ofType:"png", inDirectory:"resources")!
|
||||
|
||||
func testImencodeStringMatListOfByte() {
|
||||
var buff = [UInt8]()
|
||||
XCTAssert(Imgcodecs.imencode(ext: ".jpg", img: gray127, buf: &buff))
|
||||
XCTAssertFalse(0 == buff.count)
|
||||
}
|
||||
|
||||
func testImencodeStringMatListOfByteListOfInteger() {
|
||||
let params40:[Int32] = [ImwriteFlags.IMWRITE_JPEG_QUALITY.rawValue, 40]
|
||||
let params90:[Int32] = [ImwriteFlags.IMWRITE_JPEG_QUALITY.rawValue, 90]
|
||||
|
||||
var buff40 = [UInt8]()
|
||||
var buff90 = [UInt8]()
|
||||
|
||||
XCTAssert(Imgcodecs.imencode(ext: ".jpg", img: rgbLena, buf: &buff40, params: params40))
|
||||
XCTAssert(Imgcodecs.imencode(ext: ".jpg", img: rgbLena, buf: &buff90, params: params90))
|
||||
|
||||
XCTAssert(buff40.count > 0)
|
||||
XCTAssert(buff40.count < buff90.count)
|
||||
}
|
||||
|
||||
func testImreadString() {
|
||||
dst = Imgcodecs.imread(filename: LENA_PATH)
|
||||
XCTAssertFalse(dst.empty())
|
||||
XCTAssertEqual(3, dst.channels())
|
||||
XCTAssert(512 == dst.cols())
|
||||
XCTAssert(512 == dst.rows())
|
||||
}
|
||||
|
||||
func testImreadStringInt() {
|
||||
dst = Imgcodecs.imread(filename: LENA_PATH, flags: 0)
|
||||
XCTAssertFalse(dst.empty());
|
||||
XCTAssertEqual(1, dst.channels());
|
||||
XCTAssert(512 == dst.cols());
|
||||
XCTAssert(512 == dst.rows());
|
||||
}
|
||||
|
||||
}
|
||||
10
modules/imgcodecs/perf/perf_main.cpp
Normal file
10
modules/imgcodecs/perf/perf_main.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "perf_precomp.hpp"
|
||||
|
||||
#if defined(HAVE_HPX)
|
||||
#include <hpx/hpx_main.hpp>
|
||||
#endif
|
||||
|
||||
CV_PERF_TEST_MAIN(imgcodecs)
|
||||
10
modules/imgcodecs/perf/perf_precomp.hpp
Normal file
10
modules/imgcodecs/perf/perf_precomp.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#ifndef __OPENCV_PERF_PRECOMP_HPP__
|
||||
#define __OPENCV_PERF_PRECOMP_HPP__
|
||||
|
||||
#include "opencv2/ts.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
|
||||
#endif
|
||||
11
modules/imgcodecs/src/apple_conversions.h
Normal file
11
modules/imgcodecs/src/apple_conversions.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
#import <Accelerate/Accelerate.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <ImageIO/ImageIO.h>
|
||||
|
||||
CV_EXPORTS CGImageRef MatToCGImage(const cv::Mat& image) CF_RETURNS_RETAINED;
|
||||
CV_EXPORTS void CGImageToMat(const CGImageRef image, cv::Mat& m, bool alphaExist);
|
||||
94
modules/imgcodecs/src/apple_conversions.mm
Normal file
94
modules/imgcodecs/src/apple_conversions.mm
Normal file
@@ -0,0 +1,94 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "apple_conversions.h"
|
||||
#include "precomp.hpp"
|
||||
|
||||
CGImageRef MatToCGImage(const cv::Mat& image) {
|
||||
NSData *data = [NSData dataWithBytes:image.data
|
||||
length:image.step.p[0] * image.rows];
|
||||
|
||||
CGColorSpaceRef colorSpace;
|
||||
|
||||
if (image.elemSize() == 1) {
|
||||
colorSpace = CGColorSpaceCreateDeviceGray();
|
||||
} else {
|
||||
colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
}
|
||||
|
||||
CGDataProviderRef provider =
|
||||
CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
|
||||
|
||||
// Preserve alpha transparency, if exists
|
||||
bool alpha = image.channels() == 4;
|
||||
CGBitmapInfo bitmapInfo = (alpha ? kCGImageAlphaLast : kCGImageAlphaNone) | kCGBitmapByteOrderDefault;
|
||||
|
||||
// Creating CGImage from cv::Mat
|
||||
CGImageRef imageRef = CGImageCreate(image.cols,
|
||||
image.rows,
|
||||
8 * image.elemSize1(),
|
||||
8 * image.elemSize(),
|
||||
image.step.p[0],
|
||||
colorSpace,
|
||||
bitmapInfo,
|
||||
provider,
|
||||
NULL,
|
||||
false,
|
||||
kCGRenderingIntentDefault
|
||||
);
|
||||
|
||||
CGDataProviderRelease(provider);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
return imageRef;
|
||||
}
|
||||
|
||||
void CGImageToMat(const CGImageRef image, cv::Mat& m, bool alphaExist) {
|
||||
CGColorSpaceRef colorSpace = CGImageGetColorSpace(image);
|
||||
CGFloat cols = CGImageGetWidth(image), rows = CGImageGetHeight(image);
|
||||
CGContextRef contextRef;
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;
|
||||
if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelMonochrome)
|
||||
{
|
||||
m.create(rows, cols, CV_8UC1); // 8 bits per component, 1 channel
|
||||
bitmapInfo = kCGImageAlphaNone;
|
||||
if (!alphaExist)
|
||||
bitmapInfo = kCGImageAlphaNone;
|
||||
else
|
||||
m = cv::Scalar(0);
|
||||
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
|
||||
m.step[0], colorSpace,
|
||||
bitmapInfo);
|
||||
}
|
||||
else if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelIndexed)
|
||||
{
|
||||
// CGBitmapContextCreate() does not support indexed color spaces.
|
||||
colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
m.create(rows, cols, CV_8UC4); // 8 bits per component, 4 channels
|
||||
if (!alphaExist)
|
||||
bitmapInfo = kCGImageAlphaNoneSkipLast |
|
||||
kCGBitmapByteOrderDefault;
|
||||
else
|
||||
m = cv::Scalar(0);
|
||||
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
|
||||
m.step[0], colorSpace,
|
||||
bitmapInfo);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.create(rows, cols, CV_8UC4); // 8 bits per component, 4 channels
|
||||
if (!alphaExist)
|
||||
bitmapInfo = kCGImageAlphaNoneSkipLast |
|
||||
kCGBitmapByteOrderDefault;
|
||||
else
|
||||
m = cv::Scalar(0);
|
||||
contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
|
||||
m.step[0], colorSpace,
|
||||
bitmapInfo);
|
||||
}
|
||||
CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows),
|
||||
image);
|
||||
CGContextRelease(contextRef);
|
||||
}
|
||||
594
modules/imgcodecs/src/bitstrm.cpp
Normal file
594
modules/imgcodecs/src/bitstrm.cpp
Normal file
@@ -0,0 +1,594 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
const int BS_DEF_BLOCK_SIZE = 1<<15;
|
||||
|
||||
bool bsIsBigEndian( void )
|
||||
{
|
||||
return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0;
|
||||
}
|
||||
|
||||
///////////////////////// RBaseStream ////////////////////////////
|
||||
|
||||
bool RBaseStream::isOpened()
|
||||
{
|
||||
return m_is_opened;
|
||||
}
|
||||
|
||||
void RBaseStream::allocate()
|
||||
{
|
||||
if( !m_allocated )
|
||||
{
|
||||
m_start = new uchar[m_block_size];
|
||||
m_end = m_start + m_block_size;
|
||||
m_current = m_end;
|
||||
m_allocated = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RBaseStream::RBaseStream()
|
||||
{
|
||||
m_start = m_end = m_current = 0;
|
||||
m_file = 0;
|
||||
m_block_pos = 0;
|
||||
m_block_size = BS_DEF_BLOCK_SIZE;
|
||||
m_is_opened = false;
|
||||
m_allocated = false;
|
||||
}
|
||||
|
||||
|
||||
RBaseStream::~RBaseStream()
|
||||
{
|
||||
close(); // Close files
|
||||
release(); // free buffers
|
||||
}
|
||||
|
||||
|
||||
void RBaseStream::readBlock()
|
||||
{
|
||||
setPos( getPos() ); // normalize position
|
||||
|
||||
if( m_file == 0 )
|
||||
{
|
||||
if( m_block_pos == 0 && m_current < m_end )
|
||||
return;
|
||||
throw RBS_THROW_EOS;
|
||||
}
|
||||
|
||||
fseek( m_file, m_block_pos, SEEK_SET );
|
||||
size_t readed = fread( m_start, 1, m_block_size, m_file );
|
||||
m_end = m_start + readed;
|
||||
|
||||
if( readed == 0 || m_current >= m_end )
|
||||
throw RBS_THROW_EOS;
|
||||
}
|
||||
|
||||
|
||||
bool RBaseStream::open( const String& filename )
|
||||
{
|
||||
close();
|
||||
allocate();
|
||||
|
||||
m_file = fopen( filename.c_str(), "rb" );
|
||||
if( m_file )
|
||||
{
|
||||
m_is_opened = true;
|
||||
setPos(0);
|
||||
readBlock();
|
||||
}
|
||||
return m_file != 0;
|
||||
}
|
||||
|
||||
bool RBaseStream::open( const Mat& buf )
|
||||
{
|
||||
close();
|
||||
if( buf.empty() )
|
||||
return false;
|
||||
CV_Assert(buf.isContinuous());
|
||||
m_start = buf.data;
|
||||
m_end = m_start + buf.cols*buf.rows*buf.elemSize();
|
||||
m_allocated = false;
|
||||
m_is_opened = true;
|
||||
setPos(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RBaseStream::close()
|
||||
{
|
||||
if( m_file )
|
||||
{
|
||||
fclose( m_file );
|
||||
m_file = 0;
|
||||
}
|
||||
m_is_opened = false;
|
||||
if( !m_allocated )
|
||||
m_start = m_end = m_current = 0;
|
||||
}
|
||||
|
||||
|
||||
void RBaseStream::release()
|
||||
{
|
||||
if( m_allocated )
|
||||
delete[] m_start;
|
||||
m_start = m_end = m_current = 0;
|
||||
m_allocated = false;
|
||||
}
|
||||
|
||||
|
||||
void RBaseStream::setPos( int pos )
|
||||
{
|
||||
CV_Assert(isOpened() && pos >= 0);
|
||||
|
||||
if( !m_file )
|
||||
{
|
||||
m_current = m_start + pos;
|
||||
m_block_pos = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = pos % m_block_size;
|
||||
int old_block_pos = m_block_pos;
|
||||
m_block_pos = pos - offset;
|
||||
m_current = m_start + offset;
|
||||
if (old_block_pos != m_block_pos)
|
||||
readBlock();
|
||||
}
|
||||
|
||||
|
||||
int RBaseStream::getPos()
|
||||
{
|
||||
CV_Assert(isOpened());
|
||||
int pos = validateToInt((m_current - m_start) + m_block_pos);
|
||||
CV_Assert(pos >= m_block_pos); // overflow check
|
||||
CV_Assert(pos >= 0); // overflow check
|
||||
return pos;
|
||||
}
|
||||
|
||||
void RBaseStream::skip( int bytes )
|
||||
{
|
||||
CV_Assert(bytes >= 0);
|
||||
uchar* old = m_current;
|
||||
m_current += bytes;
|
||||
CV_Assert(m_current >= old); // overflow check
|
||||
}
|
||||
|
||||
///////////////////////// RLByteStream ////////////////////////////
|
||||
|
||||
RLByteStream::~RLByteStream()
|
||||
{
|
||||
}
|
||||
|
||||
int RLByteStream::getByte()
|
||||
{
|
||||
uchar *current = m_current;
|
||||
int val;
|
||||
|
||||
if( current >= m_end )
|
||||
{
|
||||
readBlock();
|
||||
current = m_current;
|
||||
}
|
||||
|
||||
CV_Assert(current < m_end);
|
||||
|
||||
val = *((uchar*)current);
|
||||
m_current = current + 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
int RLByteStream::getBytes( void* buffer, int count )
|
||||
{
|
||||
uchar* data = (uchar*)buffer;
|
||||
int readed = 0;
|
||||
CV_Assert(count >= 0);
|
||||
|
||||
while( count > 0 )
|
||||
{
|
||||
int l;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
l = (int)(m_end - m_current);
|
||||
if( l > count ) l = count;
|
||||
if( l > 0 ) break;
|
||||
readBlock();
|
||||
}
|
||||
memcpy( data, m_current, l );
|
||||
m_current += l;
|
||||
data += l;
|
||||
count -= l;
|
||||
readed += l;
|
||||
}
|
||||
return readed;
|
||||
}
|
||||
|
||||
|
||||
//////////// RLByteStream & RMByteStream <Get[d]word>s ////////////////
|
||||
|
||||
RMByteStream::~RMByteStream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int RLByteStream::getWord()
|
||||
{
|
||||
uchar *current = m_current;
|
||||
int val;
|
||||
|
||||
if( current+1 < m_end )
|
||||
{
|
||||
val = current[0] + (current[1] << 8);
|
||||
m_current = current + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = getByte();
|
||||
val|= getByte() << 8;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
int RLByteStream::getDWord()
|
||||
{
|
||||
uchar *current = m_current;
|
||||
int val;
|
||||
|
||||
if( current+3 < m_end )
|
||||
{
|
||||
val = current[0] + (current[1] << 8) +
|
||||
(current[2] << 16) + (current[3] << 24);
|
||||
m_current = current + 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = getByte();
|
||||
val |= getByte() << 8;
|
||||
val |= getByte() << 16;
|
||||
val |= getByte() << 24;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
int RMByteStream::getWord()
|
||||
{
|
||||
uchar *current = m_current;
|
||||
int val;
|
||||
|
||||
if( current+1 < m_end )
|
||||
{
|
||||
val = (current[0] << 8) + current[1];
|
||||
m_current = current + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = getByte() << 8;
|
||||
val|= getByte();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
int RMByteStream::getDWord()
|
||||
{
|
||||
uchar *current = m_current;
|
||||
int val;
|
||||
|
||||
if( current+3 < m_end )
|
||||
{
|
||||
val = (current[0] << 24) + (current[1] << 16) +
|
||||
(current[2] << 8) + current[3];
|
||||
m_current = current + 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = getByte() << 24;
|
||||
val |= getByte() << 16;
|
||||
val |= getByte() << 8;
|
||||
val |= getByte();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/////////////////////////// WBaseStream /////////////////////////////////
|
||||
|
||||
// WBaseStream - base class for output streams
|
||||
WBaseStream::WBaseStream()
|
||||
{
|
||||
m_start = m_end = m_current = 0;
|
||||
m_file = 0;
|
||||
m_block_pos = 0;
|
||||
m_block_size = BS_DEF_BLOCK_SIZE;
|
||||
m_is_opened = false;
|
||||
m_buf = 0;
|
||||
}
|
||||
|
||||
|
||||
WBaseStream::~WBaseStream()
|
||||
{
|
||||
close();
|
||||
release();
|
||||
}
|
||||
|
||||
|
||||
bool WBaseStream::isOpened()
|
||||
{
|
||||
return m_is_opened;
|
||||
}
|
||||
|
||||
|
||||
void WBaseStream::allocate()
|
||||
{
|
||||
if( !m_start )
|
||||
m_start = new uchar[m_block_size];
|
||||
|
||||
m_end = m_start + m_block_size;
|
||||
m_current = m_start;
|
||||
}
|
||||
|
||||
|
||||
void WBaseStream::writeBlock()
|
||||
{
|
||||
int size = (int)(m_current - m_start);
|
||||
|
||||
CV_Assert(isOpened());
|
||||
if( size == 0 )
|
||||
return;
|
||||
|
||||
if( m_buf )
|
||||
{
|
||||
size_t sz = m_buf->size();
|
||||
m_buf->resize( sz + size );
|
||||
memcpy( &(*m_buf)[sz], m_start, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
fwrite( m_start, 1, size, m_file );
|
||||
}
|
||||
m_current = m_start;
|
||||
m_block_pos += size;
|
||||
}
|
||||
|
||||
|
||||
bool WBaseStream::open( const String& filename )
|
||||
{
|
||||
close();
|
||||
allocate();
|
||||
|
||||
m_file = fopen( filename.c_str(), "wb" );
|
||||
if( m_file )
|
||||
{
|
||||
m_is_opened = true;
|
||||
m_block_pos = 0;
|
||||
m_current = m_start;
|
||||
}
|
||||
return m_file != 0;
|
||||
}
|
||||
|
||||
bool WBaseStream::open( std::vector<uchar>& buf )
|
||||
{
|
||||
close();
|
||||
allocate();
|
||||
|
||||
m_buf = &buf;
|
||||
m_is_opened = true;
|
||||
m_block_pos = 0;
|
||||
m_current = m_start;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WBaseStream::close()
|
||||
{
|
||||
if( m_is_opened )
|
||||
writeBlock();
|
||||
if( m_file )
|
||||
{
|
||||
fclose( m_file );
|
||||
m_file = 0;
|
||||
}
|
||||
m_buf = 0;
|
||||
m_is_opened = false;
|
||||
}
|
||||
|
||||
|
||||
void WBaseStream::release()
|
||||
{
|
||||
if( m_start )
|
||||
delete[] m_start;
|
||||
m_start = m_end = m_current = 0;
|
||||
}
|
||||
|
||||
|
||||
int WBaseStream::getPos()
|
||||
{
|
||||
CV_Assert(isOpened());
|
||||
return m_block_pos + (int)(m_current - m_start);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////// WLByteStream ///////////////////////////////////
|
||||
|
||||
WLByteStream::~WLByteStream()
|
||||
{
|
||||
}
|
||||
|
||||
void WLByteStream::putByte( int val )
|
||||
{
|
||||
*m_current++ = (uchar)val;
|
||||
if( m_current >= m_end )
|
||||
writeBlock();
|
||||
}
|
||||
|
||||
|
||||
void WLByteStream::putBytes( const void* buffer, int count )
|
||||
{
|
||||
uchar* data = (uchar*)buffer;
|
||||
|
||||
CV_Assert(data && m_current && count >= 0);
|
||||
|
||||
while( count )
|
||||
{
|
||||
int l = (int)(m_end - m_current);
|
||||
|
||||
if( l > count )
|
||||
l = count;
|
||||
|
||||
if( l > 0 )
|
||||
{
|
||||
memcpy( m_current, data, l );
|
||||
m_current += l;
|
||||
data += l;
|
||||
count -= l;
|
||||
}
|
||||
if( m_current == m_end )
|
||||
writeBlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WLByteStream::putWord( int val )
|
||||
{
|
||||
uchar *current = m_current;
|
||||
|
||||
if( current+1 < m_end )
|
||||
{
|
||||
current[0] = (uchar)val;
|
||||
current[1] = (uchar)(val >> 8);
|
||||
m_current = current + 2;
|
||||
if( m_current == m_end )
|
||||
writeBlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
putByte(val);
|
||||
putByte(val >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WLByteStream::putDWord( int val )
|
||||
{
|
||||
uchar *current = m_current;
|
||||
|
||||
if( current+3 < m_end )
|
||||
{
|
||||
current[0] = (uchar)val;
|
||||
current[1] = (uchar)(val >> 8);
|
||||
current[2] = (uchar)(val >> 16);
|
||||
current[3] = (uchar)(val >> 24);
|
||||
m_current = current + 4;
|
||||
if( m_current == m_end )
|
||||
writeBlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
putByte(val);
|
||||
putByte(val >> 8);
|
||||
putByte(val >> 16);
|
||||
putByte(val >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////// WMByteStream ///////////////////////////////////
|
||||
|
||||
WMByteStream::~WMByteStream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void WMByteStream::putWord( int val )
|
||||
{
|
||||
uchar *current = m_current;
|
||||
|
||||
if( current+1 < m_end )
|
||||
{
|
||||
current[0] = (uchar)(val >> 8);
|
||||
current[1] = (uchar)val;
|
||||
m_current = current + 2;
|
||||
if( m_current == m_end )
|
||||
writeBlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
putByte(val >> 8);
|
||||
putByte(val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WMByteStream::putDWord( int val )
|
||||
{
|
||||
uchar *current = m_current;
|
||||
|
||||
if( current+3 < m_end )
|
||||
{
|
||||
current[0] = (uchar)(val >> 24);
|
||||
current[1] = (uchar)(val >> 16);
|
||||
current[2] = (uchar)(val >> 8);
|
||||
current[3] = (uchar)val;
|
||||
m_current = current + 4;
|
||||
if( m_current == m_end )
|
||||
writeBlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
putByte(val >> 24);
|
||||
putByte(val >> 16);
|
||||
putByte(val >> 8);
|
||||
putByte(val);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
189
modules/imgcodecs/src/bitstrm.hpp
Normal file
189
modules/imgcodecs/src/bitstrm.hpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _BITSTRM_H_
|
||||
#define _BITSTRM_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
#define DECLARE_RBS_EXCEPTION(name) \
|
||||
class RBS_ ## name ## _Exception : public cv::Exception \
|
||||
{ \
|
||||
public: \
|
||||
RBS_ ## name ## _Exception(int code_, const String& err_, const String& func_, const String& file_, int line_) : \
|
||||
cv::Exception(code_, err_, func_, file_, line_) \
|
||||
{} \
|
||||
};
|
||||
DECLARE_RBS_EXCEPTION(THROW_EOS)
|
||||
#define RBS_THROW_EOS RBS_THROW_EOS_Exception(cv::Error::StsError, "Unexpected end of input stream", CV_Func, __FILE__, __LINE__)
|
||||
DECLARE_RBS_EXCEPTION(THROW_FORB)
|
||||
#define RBS_THROW_FORB RBS_THROW_FORB_Exception(cv::Error::StsError, "Forrbidden huffman code", CV_Func, __FILE__, __LINE__)
|
||||
DECLARE_RBS_EXCEPTION(BAD_HEADER)
|
||||
#define RBS_BAD_HEADER RBS_BAD_HEADER_Exception(cv::Error::StsError, "Invalid header", CV_Func, __FILE__, __LINE__)
|
||||
|
||||
typedef unsigned long ulong;
|
||||
|
||||
// class RBaseStream - base class for other reading streams.
|
||||
class RBaseStream
|
||||
{
|
||||
public:
|
||||
//methods
|
||||
RBaseStream();
|
||||
virtual ~RBaseStream();
|
||||
|
||||
virtual bool open( const String& filename );
|
||||
virtual bool open( const Mat& buf );
|
||||
virtual void close();
|
||||
bool isOpened();
|
||||
void setPos( int pos );
|
||||
int getPos();
|
||||
void skip( int bytes );
|
||||
|
||||
protected:
|
||||
|
||||
bool m_allocated;
|
||||
uchar* m_start;
|
||||
uchar* m_end;
|
||||
uchar* m_current;
|
||||
FILE* m_file;
|
||||
int m_block_size;
|
||||
int m_block_pos;
|
||||
bool m_is_opened;
|
||||
|
||||
virtual void readBlock();
|
||||
virtual void release();
|
||||
virtual void allocate();
|
||||
};
|
||||
|
||||
|
||||
// class RLByteStream - uchar-oriented stream.
|
||||
// l in prefix means that the least significant uchar of a multi-uchar value goes first
|
||||
class RLByteStream : public RBaseStream
|
||||
{
|
||||
public:
|
||||
virtual ~RLByteStream();
|
||||
|
||||
int getByte();
|
||||
int getBytes( void* buffer, int count );
|
||||
int getWord();
|
||||
int getDWord();
|
||||
};
|
||||
|
||||
// class RMBitStream - uchar-oriented stream.
|
||||
// m in prefix means that the most significant uchar of a multi-uchar value go first
|
||||
class RMByteStream : public RLByteStream
|
||||
{
|
||||
public:
|
||||
virtual ~RMByteStream();
|
||||
|
||||
int getWord();
|
||||
int getDWord();
|
||||
};
|
||||
|
||||
// WBaseStream - base class for output streams
|
||||
class WBaseStream
|
||||
{
|
||||
public:
|
||||
//methods
|
||||
WBaseStream();
|
||||
virtual ~WBaseStream();
|
||||
|
||||
virtual bool open( const String& filename );
|
||||
virtual bool open( std::vector<uchar>& buf );
|
||||
virtual void close();
|
||||
bool isOpened();
|
||||
int getPos();
|
||||
|
||||
protected:
|
||||
|
||||
uchar* m_start;
|
||||
uchar* m_end;
|
||||
uchar* m_current;
|
||||
int m_block_size;
|
||||
int m_block_pos;
|
||||
FILE* m_file;
|
||||
bool m_is_opened;
|
||||
std::vector<uchar>* m_buf;
|
||||
|
||||
virtual void writeBlock();
|
||||
virtual void release();
|
||||
virtual void allocate();
|
||||
};
|
||||
|
||||
|
||||
// class WLByteStream - uchar-oriented stream.
|
||||
// l in prefix means that the least significant uchar of a multi-byte value goes first
|
||||
class WLByteStream : public WBaseStream
|
||||
{
|
||||
public:
|
||||
virtual ~WLByteStream();
|
||||
|
||||
void putByte( int val );
|
||||
void putBytes( const void* buffer, int count );
|
||||
void putWord( int val );
|
||||
void putDWord( int val );
|
||||
};
|
||||
|
||||
|
||||
// class WLByteStream - uchar-oriented stream.
|
||||
// m in prefix means that the least significant uchar of a multi-byte value goes last
|
||||
class WMByteStream : public WLByteStream
|
||||
{
|
||||
public:
|
||||
virtual ~WMByteStream();
|
||||
void putWord( int val );
|
||||
void putDWord( int val );
|
||||
};
|
||||
|
||||
inline unsigned BSWAP(unsigned v)
|
||||
{
|
||||
return (v<<24)|((v&0xff00)<<8)|((v>>8)&0xff00)|((unsigned)v>>24);
|
||||
}
|
||||
|
||||
bool bsIsBigEndian( void );
|
||||
|
||||
}
|
||||
|
||||
#endif/*_BITSTRM_H_*/
|
||||
535
modules/imgcodecs/src/exif.cpp
Normal file
535
modules/imgcodecs/src/exif.cpp
Normal file
@@ -0,0 +1,535 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "exif.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
class ExifParsingError {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
ExifEntry_t::ExifEntry_t() :
|
||||
field_float(0), field_double(0), field_u32(0), field_s32(0),
|
||||
tag(INVALID_TAG), field_u16(0), field_s16(0), field_u8(0), field_s8(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ExifReader constructor
|
||||
*/
|
||||
ExifReader::ExifReader() : m_format(NONE)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ExifReader destructor
|
||||
*/
|
||||
ExifReader::~ExifReader()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get tag value by tag number
|
||||
*
|
||||
* @param [in] tag The tag number
|
||||
*
|
||||
* @return ExifEntru_t structure. Caller has to know what tag it calls in order to extract proper field from the structure ExifEntry_t
|
||||
*
|
||||
*/
|
||||
ExifEntry_t ExifReader::getTag(const ExifTagName tag) const
|
||||
{
|
||||
ExifEntry_t entry;
|
||||
std::map<int, ExifEntry_t>::const_iterator it = m_exif.find(tag);
|
||||
|
||||
if( it != m_exif.end() )
|
||||
{
|
||||
entry = it->second;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parsing the exif data buffer and prepare (internal) exif directory
|
||||
*
|
||||
* @param [in] data The data buffer to read EXIF data starting with endianness
|
||||
* @param [in] size The size of the data buffer
|
||||
*
|
||||
* @return true if parsing was successful
|
||||
* false in case of unsuccessful parsing
|
||||
*/
|
||||
bool ExifReader::parseExif(unsigned char* data, const size_t size)
|
||||
{
|
||||
// Populate m_data, then call parseExif() (private)
|
||||
if( data && size > 0 )
|
||||
{
|
||||
m_data.assign(data, data + size);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
parseExif();
|
||||
if( !m_exif.empty() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch( ExifParsingError& ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Filling m_exif member with exif directory elements
|
||||
* This is internal function and is not exposed to client
|
||||
*
|
||||
* @return The function doesn't return any value. In case of unsuccessful parsing
|
||||
* the m_exif member is not filled up
|
||||
*/
|
||||
void ExifReader::parseExif()
|
||||
{
|
||||
m_format = getFormat();
|
||||
|
||||
if( !checkTagMark() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t offset = getStartOffset();
|
||||
|
||||
size_t numEntry = getNumDirEntry( offset );
|
||||
|
||||
offset += 2; //go to start of tag fields
|
||||
|
||||
for( size_t entry = 0; entry < numEntry; entry++ )
|
||||
{
|
||||
ExifEntry_t exifEntry = parseExifEntry( offset );
|
||||
m_exif.insert( std::make_pair( exifEntry.tag, exifEntry ) );
|
||||
offset += tiffFieldSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get endianness of exif information
|
||||
* This is internal function and is not exposed to client
|
||||
*
|
||||
* @return INTEL, MOTO or NONE
|
||||
*/
|
||||
Endianess_t ExifReader::getFormat() const
|
||||
{
|
||||
if (m_data.size() < 1)
|
||||
return NONE;
|
||||
|
||||
if( m_data.size() > 1 && m_data[0] != m_data[1] )
|
||||
{
|
||||
return NONE;
|
||||
}
|
||||
|
||||
if( m_data[0] == 'I' )
|
||||
{
|
||||
return INTEL;
|
||||
}
|
||||
|
||||
if( m_data[0] == 'M' )
|
||||
{
|
||||
return MOTO;
|
||||
}
|
||||
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checking whether Tag Mark (0x002A) correspond to one contained in the Jpeg file
|
||||
* This is internal function and is not exposed to client
|
||||
*
|
||||
* @return true if tag mark equals 0x002A, false otherwise
|
||||
*/
|
||||
bool ExifReader::checkTagMark() const
|
||||
{
|
||||
uint16_t tagMark = getU16( 2 );
|
||||
|
||||
if( tagMark != tagMarkRequired )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The utility function for extracting actual offset exif IFD0 info is started from
|
||||
* This is internal function and is not exposed to client
|
||||
*
|
||||
* @return offset of IFD0 field
|
||||
*/
|
||||
uint32_t ExifReader::getStartOffset() const
|
||||
{
|
||||
return getU32( 4 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the number of Directory Entries in Jpeg file
|
||||
*
|
||||
* @return The number of directory entries
|
||||
*/
|
||||
size_t ExifReader::getNumDirEntry(const size_t offsetNumDir) const
|
||||
{
|
||||
return getU16( offsetNumDir );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parsing particular entry in exif directory
|
||||
* This is internal function and is not exposed to client
|
||||
*
|
||||
* Entries are divided into 12-bytes blocks each
|
||||
* Each block corresponds the following structure:
|
||||
*
|
||||
* +------+-------------+-------------------+------------------------+
|
||||
* | Type | Data format | Num of components | Data or offset to data |
|
||||
* +======+=============+===================+========================+
|
||||
* | TTTT | ffff | NNNNNNNN | DDDDDDDD |
|
||||
* +------+-------------+-------------------+------------------------+
|
||||
*
|
||||
* Details can be found here: http://www.media.mit.edu/pia/Research/deepview/exif.html
|
||||
*
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return ExifEntry_t structure which corresponds to particular entry
|
||||
*
|
||||
*/
|
||||
ExifEntry_t ExifReader::parseExifEntry(const size_t offset)
|
||||
{
|
||||
ExifEntry_t entry;
|
||||
uint16_t tagNum = getExifTag( offset );
|
||||
entry.tag = tagNum;
|
||||
|
||||
switch( tagNum )
|
||||
{
|
||||
case IMAGE_DESCRIPTION:
|
||||
entry.field_str = getString( offset );
|
||||
break;
|
||||
case MAKE:
|
||||
entry.field_str = getString( offset );
|
||||
break;
|
||||
case MODEL:
|
||||
entry.field_str = getString( offset );
|
||||
break;
|
||||
case ORIENTATION:
|
||||
entry.field_u16 = getOrientation( offset );
|
||||
break;
|
||||
case XRESOLUTION:
|
||||
entry.field_u_rational = getResolution( offset );
|
||||
break;
|
||||
case YRESOLUTION:
|
||||
entry.field_u_rational = getResolution( offset );
|
||||
break;
|
||||
case RESOLUTION_UNIT:
|
||||
entry.field_u16 = getResolutionUnit( offset );
|
||||
break;
|
||||
case SOFTWARE:
|
||||
entry.field_str = getString( offset );
|
||||
break;
|
||||
case DATE_TIME:
|
||||
entry.field_str = getString( offset );
|
||||
break;
|
||||
case WHITE_POINT:
|
||||
entry.field_u_rational = getWhitePoint( offset );
|
||||
break;
|
||||
case PRIMARY_CHROMATICIES:
|
||||
entry.field_u_rational = getPrimaryChromaticies( offset );
|
||||
break;
|
||||
case Y_CB_CR_COEFFICIENTS:
|
||||
entry.field_u_rational = getYCbCrCoeffs( offset );
|
||||
break;
|
||||
case Y_CB_CR_POSITIONING:
|
||||
entry.field_u16 = getYCbCrPos( offset );
|
||||
break;
|
||||
case REFERENCE_BLACK_WHITE:
|
||||
entry.field_u_rational = getRefBW( offset );
|
||||
break;
|
||||
case COPYRIGHT:
|
||||
entry.field_str = getString( offset );
|
||||
break;
|
||||
case EXIF_OFFSET:
|
||||
break;
|
||||
default:
|
||||
entry.tag = INVALID_TAG;
|
||||
break;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get tag number from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return tag number
|
||||
*/
|
||||
uint16_t ExifReader::getExifTag(const size_t offset) const
|
||||
{
|
||||
return getU16( offset );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get string information from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return string value
|
||||
*/
|
||||
std::string ExifReader::getString(const size_t offset) const
|
||||
{
|
||||
size_t size = getU32( offset + 4 );
|
||||
size_t dataOffset = 8; // position of data in the field
|
||||
if( size > maxDataSize )
|
||||
{
|
||||
dataOffset = getU32( offset + 8 );
|
||||
}
|
||||
if (dataOffset > m_data.size() || dataOffset + size > m_data.size()) {
|
||||
throw ExifParsingError();
|
||||
}
|
||||
std::vector<uint8_t>::const_iterator it = m_data.begin() + dataOffset;
|
||||
std::string result( it, it + size ); //copy vector content into result
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get unsigned short data from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return Unsigned short data
|
||||
*/
|
||||
uint16_t ExifReader::getU16(const size_t offset) const
|
||||
{
|
||||
if (offset + 1 >= m_data.size())
|
||||
throw ExifParsingError();
|
||||
|
||||
if( m_format == INTEL )
|
||||
{
|
||||
return m_data[offset] + ( m_data[offset + 1] << 8 );
|
||||
}
|
||||
return ( m_data[offset] << 8 ) + m_data[offset + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get unsigned 32-bit data from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return Unsigned 32-bit data
|
||||
*/
|
||||
uint32_t ExifReader::getU32(const size_t offset) const
|
||||
{
|
||||
if (offset + 3 >= m_data.size())
|
||||
throw ExifParsingError();
|
||||
|
||||
if( m_format == INTEL )
|
||||
{
|
||||
return m_data[offset] +
|
||||
( m_data[offset + 1] << 8 ) +
|
||||
( m_data[offset + 2] << 16 ) +
|
||||
( m_data[offset + 3] << 24 );
|
||||
}
|
||||
|
||||
return ( m_data[offset] << 24 ) +
|
||||
( m_data[offset + 1] << 16 ) +
|
||||
( m_data[offset + 2] << 8 ) +
|
||||
m_data[offset + 3];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get unsigned rational data from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return Unsigned rational data
|
||||
*
|
||||
* "rational" means a fractional value, it contains 2 signed/unsigned long integer value,
|
||||
* and the first represents the numerator, the second, the denominator.
|
||||
*/
|
||||
u_rational_t ExifReader::getURational(const size_t offset) const
|
||||
{
|
||||
uint32_t numerator = getU32( offset );
|
||||
uint32_t denominator = getU32( offset + 4 );
|
||||
|
||||
return std::make_pair( numerator, denominator );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get orientation information from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return orientation number
|
||||
*/
|
||||
uint16_t ExifReader::getOrientation(const size_t offset) const
|
||||
{
|
||||
return getU16( offset + 8 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get resolution information from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return resolution value
|
||||
*/
|
||||
std::vector<u_rational_t> ExifReader::getResolution(const size_t offset) const
|
||||
{
|
||||
std::vector<u_rational_t> result;
|
||||
uint32_t rationalOffset = getU32( offset + 8 );
|
||||
result.push_back( getURational( rationalOffset ) );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get resolution unit from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return resolution unit value
|
||||
*/
|
||||
uint16_t ExifReader::getResolutionUnit(const size_t offset) const
|
||||
{
|
||||
return getU16( offset + 8 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get White Point information from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return White Point value
|
||||
*
|
||||
* If the image uses CIE Standard Illumination D65(known as international
|
||||
* standard of 'daylight'), the values are '3127/10000,3290/10000'.
|
||||
*/
|
||||
std::vector<u_rational_t> ExifReader::getWhitePoint(const size_t offset) const
|
||||
{
|
||||
std::vector<u_rational_t> result;
|
||||
uint32_t rationalOffset = getU32( offset + 8 );
|
||||
result.push_back( getURational( rationalOffset ) );
|
||||
result.push_back( getURational( rationalOffset + 8 ) );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Primary Chromaticies information from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return vector with primary chromaticies values
|
||||
*
|
||||
*/
|
||||
std::vector<u_rational_t> ExifReader::getPrimaryChromaticies(const size_t offset) const
|
||||
{
|
||||
std::vector<u_rational_t> result;
|
||||
uint32_t rationalOffset = getU32( offset + 8 );
|
||||
for( size_t i = 0; i < primaryChromaticiesComponents; i++ )
|
||||
{
|
||||
result.push_back( getURational( rationalOffset ) );
|
||||
rationalOffset += 8;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get YCbCr Coefficients information from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return vector with YCbCr coefficients values
|
||||
*
|
||||
*/
|
||||
std::vector<u_rational_t> ExifReader::getYCbCrCoeffs(const size_t offset) const
|
||||
{
|
||||
std::vector<u_rational_t> result;
|
||||
uint32_t rationalOffset = getU32( offset + 8 );
|
||||
for( size_t i = 0; i < ycbcrCoeffs; i++ )
|
||||
{
|
||||
result.push_back( getURational( rationalOffset ) );
|
||||
rationalOffset += 8;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get YCbCr Positioning information from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return vector with YCbCr positioning value
|
||||
*
|
||||
*/
|
||||
uint16_t ExifReader::getYCbCrPos(const size_t offset) const
|
||||
{
|
||||
return getU16( offset + 8 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Reference Black&White point information from raw exif data
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] offset Offset to entry in bytes inside raw exif data
|
||||
* @return vector with reference BW points
|
||||
*
|
||||
* In case of YCbCr format, first 2 show black/white of Y, next 2 are Cb,
|
||||
* last 2 are Cr. In case of RGB format, first 2 show black/white of R,
|
||||
* next 2 are G, last 2 are B.
|
||||
*
|
||||
*/
|
||||
std::vector<u_rational_t> ExifReader::getRefBW(const size_t offset) const
|
||||
{
|
||||
const size_t rationalFieldSize = 8;
|
||||
std::vector<u_rational_t> result;
|
||||
uint32_t rationalOffset = getU32( offset + rationalFieldSize );
|
||||
for( size_t i = 0; i < refBWComponents; i++ )
|
||||
{
|
||||
result.push_back( getURational( rationalOffset ) );
|
||||
rationalOffset += rationalFieldSize;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} //namespace cv
|
||||
233
modules/imgcodecs/src/exif.hpp
Normal file
233
modules/imgcodecs/src/exif.hpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
|
||||
#ifndef _OPENCV_EXIF_HPP_
|
||||
#define _OPENCV_EXIF_HPP_
|
||||
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Base Exif tags used by IFD0 (main image)
|
||||
*/
|
||||
enum ExifTagName
|
||||
{
|
||||
IMAGE_DESCRIPTION = 0x010E, ///< Image Description: ASCII string
|
||||
MAKE = 0x010F, ///< Description of manufacturer: ASCII string
|
||||
MODEL = 0x0110, ///< Description of camera model: ASCII string
|
||||
ORIENTATION = 0x0112, ///< Orientation of the image: unsigned short
|
||||
XRESOLUTION = 0x011A, ///< Resolution of the image across X axis: unsigned rational
|
||||
YRESOLUTION = 0x011B, ///< Resolution of the image across Y axis: unsigned rational
|
||||
RESOLUTION_UNIT = 0x0128, ///< Resolution units. '1' no-unit, '2' inch, '3' centimeter
|
||||
SOFTWARE = 0x0131, ///< Shows firmware(internal software of digicam) version number
|
||||
DATE_TIME = 0x0132, ///< Date/Time of image was last modified
|
||||
WHITE_POINT = 0x013E, ///< Chromaticity of white point of the image
|
||||
PRIMARY_CHROMATICIES = 0x013F, ///< Chromaticity of the primaries of the image
|
||||
Y_CB_CR_COEFFICIENTS = 0x0211, ///< constant to translate an image from YCbCr to RGB format
|
||||
Y_CB_CR_POSITIONING = 0x0213, ///< Chroma sample point of subsampling pixel array
|
||||
REFERENCE_BLACK_WHITE = 0x0214, ///< Reference value of black point/white point
|
||||
COPYRIGHT = 0x8298, ///< Copyright information
|
||||
EXIF_OFFSET = 0x8769, ///< Offset to Exif Sub IFD
|
||||
INVALID_TAG = 0xFFFF ///< Shows that the tag was not recognized
|
||||
};
|
||||
|
||||
enum Endianess_t
|
||||
{
|
||||
INTEL = 0x49,
|
||||
MOTO = 0x4D,
|
||||
NONE = 0x00
|
||||
};
|
||||
|
||||
typedef std::pair<uint32_t, uint32_t> u_rational_t;
|
||||
|
||||
/**
|
||||
* @brief Entry which contains possible values for different exif tags
|
||||
*/
|
||||
struct ExifEntry_t
|
||||
{
|
||||
ExifEntry_t();
|
||||
|
||||
std::vector<u_rational_t> field_u_rational; ///< vector of rational fields
|
||||
std::string field_str; ///< any kind of textual information
|
||||
|
||||
float field_float; ///< Currently is not used
|
||||
double field_double; ///< Currently is not used
|
||||
|
||||
uint32_t field_u32; ///< Unsigned 32-bit value
|
||||
int32_t field_s32; ///< Signed 32-bit value
|
||||
|
||||
uint16_t tag; ///< Tag number
|
||||
|
||||
uint16_t field_u16; ///< Unsigned 16-bit value
|
||||
int16_t field_s16; ///< Signed 16-bit value
|
||||
uint8_t field_u8; ///< Unsigned 8-bit value
|
||||
int8_t field_s8; ///< Signed 8-bit value
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Picture orientation which may be taken from EXIF
|
||||
* Orientation usually matters when the picture is taken by
|
||||
* smartphone or other camera with orientation sensor support
|
||||
* Corresponds to EXIF 2.3 Specification
|
||||
*/
|
||||
enum ImageOrientation
|
||||
{
|
||||
IMAGE_ORIENTATION_TL = 1, ///< Horizontal (normal)
|
||||
IMAGE_ORIENTATION_TR = 2, ///< Mirrored horizontal
|
||||
IMAGE_ORIENTATION_BR = 3, ///< Rotate 180
|
||||
IMAGE_ORIENTATION_BL = 4, ///< Mirrored vertical
|
||||
IMAGE_ORIENTATION_LT = 5, ///< Mirrored horizontal & rotate 270 CW
|
||||
IMAGE_ORIENTATION_RT = 6, ///< Rotate 90 CW
|
||||
IMAGE_ORIENTATION_RB = 7, ///< Mirrored horizontal & rotate 90 CW
|
||||
IMAGE_ORIENTATION_LB = 8 ///< Rotate 270 CW
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reading exif information from Jpeg file
|
||||
*
|
||||
* Usage example for getting the orientation of the image:
|
||||
*
|
||||
* @code
|
||||
* std::ifstream stream(filename,std::ios_base::in | std::ios_base::binary);
|
||||
* ExifReader reader(stream);
|
||||
* if( reader.parse() )
|
||||
* {
|
||||
* int orientation = reader.getTag(Orientation).field_u16;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
class ExifReader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief ExifReader constructor. Constructs an object of exif reader
|
||||
*/
|
||||
ExifReader();
|
||||
~ExifReader();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse the file with exif info
|
||||
*
|
||||
* @param [in] data The data buffer to read EXIF data starting with endianness
|
||||
* @param [in] size The size of the data buffer
|
||||
*
|
||||
* @return true if successful parsing
|
||||
* false if parsing error
|
||||
*/
|
||||
|
||||
bool parseExif(unsigned char* data, const size_t size);
|
||||
|
||||
/**
|
||||
* @brief Get tag info by tag number
|
||||
*
|
||||
* @param [in] tag The tag number
|
||||
* @return ExifEntru_t structure. Caller has to know what tag it calls in order to extract proper field from the structure ExifEntry_t
|
||||
*/
|
||||
ExifEntry_t getTag( const ExifTagName tag ) const;
|
||||
|
||||
|
||||
private:
|
||||
std::vector<unsigned char> m_data;
|
||||
std::map<int, ExifEntry_t > m_exif;
|
||||
Endianess_t m_format;
|
||||
|
||||
void parseExif();
|
||||
bool checkTagMark() const;
|
||||
|
||||
size_t getNumDirEntry( const size_t offsetNumDir ) const;
|
||||
uint32_t getStartOffset() const;
|
||||
uint16_t getExifTag( const size_t offset ) const;
|
||||
uint16_t getU16( const size_t offset ) const;
|
||||
uint32_t getU32( const size_t offset ) const;
|
||||
uint16_t getOrientation( const size_t offset ) const;
|
||||
uint16_t getResolutionUnit( const size_t offset ) const;
|
||||
uint16_t getYCbCrPos( const size_t offset ) const;
|
||||
|
||||
Endianess_t getFormat() const;
|
||||
|
||||
ExifEntry_t parseExifEntry( const size_t offset );
|
||||
|
||||
u_rational_t getURational( const size_t offset ) const;
|
||||
|
||||
std::string getString( const size_t offset ) const;
|
||||
std::vector<u_rational_t> getResolution( const size_t offset ) const;
|
||||
std::vector<u_rational_t> getWhitePoint( const size_t offset ) const;
|
||||
std::vector<u_rational_t> getPrimaryChromaticies( const size_t offset ) const;
|
||||
std::vector<u_rational_t> getYCbCrCoeffs( const size_t offset ) const;
|
||||
std::vector<u_rational_t> getRefBW( const size_t offset ) const;
|
||||
|
||||
private:
|
||||
static const uint16_t tagMarkRequired = 0x2A;
|
||||
|
||||
//max size of data in tag.
|
||||
//'DDDDDDDD' contains the value of that Tag. If its size is over 4bytes,
|
||||
//'DDDDDDDD' contains the offset to data stored address.
|
||||
static const size_t maxDataSize = 4;
|
||||
|
||||
//bytes per tag field
|
||||
static const size_t tiffFieldSize = 12;
|
||||
|
||||
//number of primary chromaticies components
|
||||
static const size_t primaryChromaticiesComponents = 6;
|
||||
|
||||
//number of YCbCr coefficients in field
|
||||
static const size_t ycbcrCoeffs = 3;
|
||||
|
||||
//number of Reference Black&White components
|
||||
static const size_t refBWComponents = 6;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif /* _OPENCV_EXIF_HPP_ */
|
||||
156
modules/imgcodecs/src/grfmt_base.cpp
Normal file
156
modules/imgcodecs/src/grfmt_base.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
BaseImageDecoder::BaseImageDecoder()
|
||||
{
|
||||
m_width = m_height = 0;
|
||||
m_type = -1;
|
||||
m_buf_supported = false;
|
||||
m_scale_denom = 1;
|
||||
}
|
||||
|
||||
|
||||
ExifEntry_t BaseImageDecoder::getExifTag(const ExifTagName tag) const
|
||||
{
|
||||
return m_exif.getTag(tag);
|
||||
}
|
||||
bool BaseImageDecoder::setSource( const String& filename )
|
||||
{
|
||||
m_filename = filename;
|
||||
m_buf.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseImageDecoder::setSource( const Mat& buf )
|
||||
{
|
||||
if( !m_buf_supported )
|
||||
return false;
|
||||
m_filename = String();
|
||||
m_buf = buf;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t BaseImageDecoder::signatureLength() const
|
||||
{
|
||||
return m_signature.size();
|
||||
}
|
||||
|
||||
bool BaseImageDecoder::checkSignature( const String& signature ) const
|
||||
{
|
||||
size_t len = signatureLength();
|
||||
return signature.size() >= len && memcmp( signature.c_str(), m_signature.c_str(), len ) == 0;
|
||||
}
|
||||
|
||||
int BaseImageDecoder::setScale( const int& scale_denom )
|
||||
{
|
||||
int temp = m_scale_denom;
|
||||
m_scale_denom = scale_denom;
|
||||
return temp;
|
||||
}
|
||||
|
||||
ImageDecoder BaseImageDecoder::newDecoder() const
|
||||
{
|
||||
return ImageDecoder();
|
||||
}
|
||||
|
||||
BaseImageEncoder::BaseImageEncoder()
|
||||
{
|
||||
m_buf = 0;
|
||||
m_buf_supported = false;
|
||||
}
|
||||
|
||||
bool BaseImageEncoder::isFormatSupported( int depth ) const
|
||||
{
|
||||
return depth == CV_8U;
|
||||
}
|
||||
|
||||
String BaseImageEncoder::getDescription() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
bool BaseImageEncoder::setDestination( const String& filename )
|
||||
{
|
||||
m_filename = filename;
|
||||
m_buf = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseImageEncoder::setDestination( std::vector<uchar>& buf )
|
||||
{
|
||||
if( !m_buf_supported )
|
||||
return false;
|
||||
m_buf = &buf;
|
||||
m_buf->clear();
|
||||
m_filename = String();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseImageEncoder::writemulti(const std::vector<Mat>&, const std::vector<int>& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageEncoder BaseImageEncoder::newEncoder() const
|
||||
{
|
||||
return ImageEncoder();
|
||||
}
|
||||
|
||||
void BaseImageEncoder::throwOnEror() const
|
||||
{
|
||||
if(!m_last_error.empty())
|
||||
{
|
||||
String msg = "Raw image encoder error: " + m_last_error;
|
||||
CV_Error( Error::BadImageSize, msg.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
126
modules/imgcodecs/src/grfmt_base.hpp
Normal file
126
modules/imgcodecs/src/grfmt_base.hpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_BASE_H_
|
||||
#define _GRFMT_BASE_H_
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
#include "exif.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
class BaseImageDecoder;
|
||||
class BaseImageEncoder;
|
||||
typedef Ptr<BaseImageEncoder> ImageEncoder;
|
||||
typedef Ptr<BaseImageDecoder> ImageDecoder;
|
||||
|
||||
///////////////////////////////// base class for decoders ////////////////////////
|
||||
class BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
BaseImageDecoder();
|
||||
virtual ~BaseImageDecoder() {}
|
||||
|
||||
int width() const { return m_width; }
|
||||
int height() const { return m_height; }
|
||||
virtual int type() const { return m_type; }
|
||||
|
||||
ExifEntry_t getExifTag(const ExifTagName tag) const;
|
||||
virtual bool setSource( const String& filename );
|
||||
virtual bool setSource( const Mat& buf );
|
||||
virtual int setScale( const int& scale_denom );
|
||||
virtual bool readHeader() = 0;
|
||||
virtual bool readData( Mat& img ) = 0;
|
||||
|
||||
/// Called after readData to advance to the next page, if any.
|
||||
virtual bool nextPage() { return false; }
|
||||
|
||||
virtual size_t signatureLength() const;
|
||||
virtual bool checkSignature( const String& signature ) const;
|
||||
virtual ImageDecoder newDecoder() const;
|
||||
|
||||
protected:
|
||||
int m_width; // width of the image ( filled by readHeader )
|
||||
int m_height; // height of the image ( filled by readHeader )
|
||||
int m_type;
|
||||
int m_scale_denom;
|
||||
String m_filename;
|
||||
String m_signature;
|
||||
Mat m_buf;
|
||||
bool m_buf_supported;
|
||||
ExifReader m_exif;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////// base class for encoders ////////////////////////////
|
||||
class BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
BaseImageEncoder();
|
||||
virtual ~BaseImageEncoder() {}
|
||||
virtual bool isFormatSupported( int depth ) const;
|
||||
|
||||
virtual bool setDestination( const String& filename );
|
||||
virtual bool setDestination( std::vector<uchar>& buf );
|
||||
virtual bool write( const Mat& img, const std::vector<int>& params ) = 0;
|
||||
virtual bool writemulti(const std::vector<Mat>& img_vec, const std::vector<int>& params);
|
||||
|
||||
virtual String getDescription() const;
|
||||
virtual ImageEncoder newEncoder() const;
|
||||
|
||||
virtual void throwOnEror() const;
|
||||
|
||||
protected:
|
||||
String m_description;
|
||||
|
||||
String m_filename;
|
||||
std::vector<uchar>* m_buf;
|
||||
bool m_buf_supported;
|
||||
|
||||
String m_last_error;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif/*_GRFMT_BASE_H_*/
|
||||
588
modules/imgcodecs/src/grfmt_bmp.cpp
Normal file
588
modules/imgcodecs/src/grfmt_bmp.cpp
Normal file
@@ -0,0 +1,588 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "grfmt_bmp.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
static const char* fmtSignBmp = "BM";
|
||||
|
||||
/************************ BMP decoder *****************************/
|
||||
|
||||
BmpDecoder::BmpDecoder()
|
||||
{
|
||||
m_signature = fmtSignBmp;
|
||||
m_offset = -1;
|
||||
m_buf_supported = true;
|
||||
m_origin = ORIGIN_TL;
|
||||
m_bpp = 0;
|
||||
m_rle_code = BMP_RGB;
|
||||
}
|
||||
|
||||
|
||||
BmpDecoder::~BmpDecoder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void BmpDecoder::close()
|
||||
{
|
||||
m_strm.close();
|
||||
}
|
||||
|
||||
ImageDecoder BmpDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<BmpDecoder>();
|
||||
}
|
||||
|
||||
bool BmpDecoder::readHeader()
|
||||
{
|
||||
bool result = false;
|
||||
bool iscolor = false;
|
||||
|
||||
if( !m_buf.empty() )
|
||||
{
|
||||
if( !m_strm.open( m_buf ) )
|
||||
return false;
|
||||
}
|
||||
else if( !m_strm.open( m_filename ))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
m_strm.skip( 10 );
|
||||
m_offset = m_strm.getDWord();
|
||||
|
||||
int size = m_strm.getDWord();
|
||||
CV_Assert(size > 0); // overflow, 2Gb limit
|
||||
|
||||
if( size >= 36 )
|
||||
{
|
||||
m_width = m_strm.getDWord();
|
||||
m_height = m_strm.getDWord();
|
||||
m_bpp = m_strm.getDWord() >> 16;
|
||||
int m_rle_code_ = m_strm.getDWord();
|
||||
CV_Assert(m_rle_code_ >= 0 && m_rle_code_ <= BMP_BITFIELDS);
|
||||
m_rle_code = (BmpCompression)m_rle_code_;
|
||||
m_strm.skip(12);
|
||||
int clrused = m_strm.getDWord();
|
||||
m_strm.skip( size - 36 );
|
||||
|
||||
if( m_width > 0 && m_height != 0 &&
|
||||
(((m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
|
||||
m_bpp == 24 || m_bpp == 32 ) && m_rle_code == BMP_RGB) ||
|
||||
((m_bpp == 16 || m_bpp == 32) && (m_rle_code == BMP_RGB || m_rle_code == BMP_BITFIELDS)) ||
|
||||
(m_bpp == 4 && m_rle_code == BMP_RLE4) ||
|
||||
(m_bpp == 8 && m_rle_code == BMP_RLE8)))
|
||||
{
|
||||
iscolor = true;
|
||||
result = true;
|
||||
|
||||
if( m_bpp <= 8 )
|
||||
{
|
||||
CV_Assert(clrused >= 0 && clrused <= 256);
|
||||
memset(m_palette, 0, sizeof(m_palette));
|
||||
m_strm.getBytes(m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
|
||||
iscolor = IsColorPalette( m_palette, m_bpp );
|
||||
}
|
||||
else if( m_bpp == 16 && m_rle_code == BMP_BITFIELDS )
|
||||
{
|
||||
int redmask = m_strm.getDWord();
|
||||
int greenmask = m_strm.getDWord();
|
||||
int bluemask = m_strm.getDWord();
|
||||
|
||||
if( bluemask == 0x1f && greenmask == 0x3e0 && redmask == 0x7c00 )
|
||||
m_bpp = 15;
|
||||
else if( bluemask == 0x1f && greenmask == 0x7e0 && redmask == 0xf800 )
|
||||
;
|
||||
else
|
||||
result = false;
|
||||
}
|
||||
else if (m_bpp == 32 && m_rle_code == BMP_BITFIELDS)
|
||||
{
|
||||
// 32bit BMP not require to check something - we can simply allow it to use
|
||||
;
|
||||
}
|
||||
else if( m_bpp == 16 && m_rle_code == BMP_RGB )
|
||||
m_bpp = 15;
|
||||
}
|
||||
}
|
||||
else if( size == 12 )
|
||||
{
|
||||
m_width = m_strm.getWord();
|
||||
m_height = m_strm.getWord();
|
||||
m_bpp = m_strm.getDWord() >> 16;
|
||||
m_rle_code = BMP_RGB;
|
||||
|
||||
if( m_width > 0 && m_height != 0 &&
|
||||
(m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
|
||||
m_bpp == 24 || m_bpp == 32 ))
|
||||
{
|
||||
if( m_bpp <= 8 )
|
||||
{
|
||||
uchar buffer[256*3];
|
||||
int j, clrused = 1 << m_bpp;
|
||||
m_strm.getBytes( buffer, clrused*3 );
|
||||
for( j = 0; j < clrused; j++ )
|
||||
{
|
||||
m_palette[j].b = buffer[3*j+0];
|
||||
m_palette[j].g = buffer[3*j+1];
|
||||
m_palette[j].r = buffer[3*j+2];
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
// in 32 bit case alpha channel is used - so require CV_8UC4 type
|
||||
m_type = iscolor ? (m_bpp == 32 ? CV_8UC4 : CV_8UC3 ) : CV_8UC1;
|
||||
m_origin = m_height > 0 ? ORIGIN_BL : ORIGIN_TL;
|
||||
m_height = std::abs(m_height);
|
||||
|
||||
if( !result )
|
||||
{
|
||||
m_offset = -1;
|
||||
m_width = m_height = -1;
|
||||
m_strm.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool BmpDecoder::readData( Mat& img )
|
||||
{
|
||||
uchar* data = img.ptr();
|
||||
int step = validateToInt(img.step);
|
||||
bool color = img.channels() > 1;
|
||||
uchar gray_palette[256] = {0};
|
||||
bool result = false;
|
||||
int src_pitch = ((m_width*(m_bpp != 15 ? m_bpp : 16) + 7)/8 + 3) & -4;
|
||||
int nch = color ? 3 : 1;
|
||||
int y, width3 = m_width*nch;
|
||||
|
||||
// FIXIT: use safe pointer arithmetic (avoid 'int'), use size_t, intptr_t, etc
|
||||
CV_Assert(((uint64)m_height * m_width * nch < (CV_BIG_UINT(1) << 30)) && "BMP reader implementation doesn't support large images >= 1Gb");
|
||||
|
||||
if( m_offset < 0 || !m_strm.isOpened())
|
||||
return false;
|
||||
|
||||
if( m_origin == ORIGIN_BL )
|
||||
{
|
||||
data += (m_height - 1)*(size_t)step;
|
||||
step = -step;
|
||||
}
|
||||
|
||||
AutoBuffer<uchar> _src, _bgr;
|
||||
_src.allocate(src_pitch + 32);
|
||||
|
||||
if( !color )
|
||||
{
|
||||
if( m_bpp <= 8 )
|
||||
{
|
||||
CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
|
||||
}
|
||||
_bgr.allocate(m_width*3 + 32);
|
||||
}
|
||||
uchar *src = _src.data(), *bgr = _bgr.data();
|
||||
|
||||
try
|
||||
{
|
||||
m_strm.setPos( m_offset );
|
||||
|
||||
switch( m_bpp )
|
||||
{
|
||||
/************************* 1 BPP ************************/
|
||||
case 1:
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
FillColorRow1( color ? data : bgr, src, m_width, m_palette );
|
||||
if( !color )
|
||||
icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, Size(m_width,1) );
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
|
||||
/************************* 4 BPP ************************/
|
||||
case 4:
|
||||
if( m_rle_code == BMP_RGB )
|
||||
{
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
if( color )
|
||||
FillColorRow4( data, src, m_width, m_palette );
|
||||
else
|
||||
FillGrayRow4( data, src, m_width, gray_palette );
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
else if( m_rle_code == BMP_RLE4 ) // rle4 compression
|
||||
{
|
||||
uchar* line_end = data + width3;
|
||||
y = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int code = m_strm.getWord();
|
||||
const int len = code & 255;
|
||||
code >>= 8;
|
||||
if( len != 0 ) // encoded mode
|
||||
{
|
||||
PaletteEntry clr[2];
|
||||
uchar gray_clr[2];
|
||||
int t = 0;
|
||||
|
||||
clr[0] = m_palette[code >> 4];
|
||||
clr[1] = m_palette[code & 15];
|
||||
gray_clr[0] = gray_palette[code >> 4];
|
||||
gray_clr[1] = gray_palette[code & 15];
|
||||
|
||||
uchar* end = data + len*nch;
|
||||
if( end > line_end ) goto decode_rle4_bad;
|
||||
do
|
||||
{
|
||||
if( color )
|
||||
WRITE_PIX( data, clr[t] );
|
||||
else
|
||||
*data = gray_clr[t];
|
||||
t ^= 1;
|
||||
}
|
||||
while( (data += nch) < end );
|
||||
}
|
||||
else if( code > 2 ) // absolute mode
|
||||
{
|
||||
if( data + code*nch > line_end ) goto decode_rle4_bad;
|
||||
int sz = (((code + 1)>>1) + 1) & (~1);
|
||||
CV_Assert((size_t)sz < _src.size());
|
||||
m_strm.getBytes(src, sz);
|
||||
if( color )
|
||||
data = FillColorRow4( data, src, code, m_palette );
|
||||
else
|
||||
data = FillGrayRow4( data, src, code, gray_palette );
|
||||
}
|
||||
else
|
||||
{
|
||||
int x_shift3 = (int)(line_end - data);
|
||||
|
||||
if( code == 2 )
|
||||
{
|
||||
x_shift3 = m_strm.getByte()*nch;
|
||||
m_strm.getByte();
|
||||
}
|
||||
|
||||
if( color )
|
||||
data = FillUniColor( data, line_end, step, width3,
|
||||
y, m_height, x_shift3,
|
||||
m_palette[0] );
|
||||
else
|
||||
data = FillUniGray( data, line_end, step, width3,
|
||||
y, m_height, x_shift3,
|
||||
gray_palette[0] );
|
||||
|
||||
if( y >= m_height )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result = true;
|
||||
decode_rle4_bad: ;
|
||||
}
|
||||
break;
|
||||
|
||||
/************************* 8 BPP ************************/
|
||||
case 8:
|
||||
if( m_rle_code == BMP_RGB )
|
||||
{
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
if( color )
|
||||
FillColorRow8( data, src, m_width, m_palette );
|
||||
else
|
||||
FillGrayRow8( data, src, m_width, gray_palette );
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
else if( m_rle_code == BMP_RLE8 ) // rle8 compression
|
||||
{
|
||||
uchar* line_end = data + width3;
|
||||
int line_end_flag = 0;
|
||||
y = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int code = m_strm.getWord();
|
||||
int len = code & 255;
|
||||
code >>= 8;
|
||||
if( len != 0 ) // encoded mode
|
||||
{
|
||||
int prev_y = y;
|
||||
len *= nch;
|
||||
|
||||
if( data + len > line_end )
|
||||
goto decode_rle8_bad;
|
||||
|
||||
if( color )
|
||||
data = FillUniColor( data, line_end, step, width3,
|
||||
y, m_height, len,
|
||||
m_palette[code] );
|
||||
else
|
||||
data = FillUniGray( data, line_end, step, width3,
|
||||
y, m_height, len,
|
||||
gray_palette[code] );
|
||||
|
||||
line_end_flag = y - prev_y;
|
||||
|
||||
if( y >= m_height )
|
||||
break;
|
||||
}
|
||||
else if( code > 2 ) // absolute mode
|
||||
{
|
||||
int prev_y = y;
|
||||
int code3 = code*nch;
|
||||
|
||||
if( data + code3 > line_end )
|
||||
goto decode_rle8_bad;
|
||||
int sz = (code + 1) & (~1);
|
||||
CV_Assert((size_t)sz < _src.size());
|
||||
m_strm.getBytes(src, sz);
|
||||
if( color )
|
||||
data = FillColorRow8( data, src, code, m_palette );
|
||||
else
|
||||
data = FillGrayRow8( data, src, code, gray_palette );
|
||||
|
||||
line_end_flag = y - prev_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
int x_shift3 = (int)(line_end - data);
|
||||
int y_shift = m_height - y;
|
||||
|
||||
if( code || !line_end_flag || x_shift3 < width3 )
|
||||
{
|
||||
if( code == 2 )
|
||||
{
|
||||
x_shift3 = m_strm.getByte()*nch;
|
||||
y_shift = m_strm.getByte();
|
||||
}
|
||||
|
||||
x_shift3 += (y_shift * width3) & ((code == 0) - 1);
|
||||
|
||||
if( y >= m_height )
|
||||
break;
|
||||
|
||||
if( color )
|
||||
data = FillUniColor( data, line_end, step, width3,
|
||||
y, m_height, x_shift3,
|
||||
m_palette[0] );
|
||||
else
|
||||
data = FillUniGray( data, line_end, step, width3,
|
||||
y, m_height, x_shift3,
|
||||
gray_palette[0] );
|
||||
|
||||
if( y >= m_height )
|
||||
break;
|
||||
}
|
||||
|
||||
line_end_flag = 0;
|
||||
if( y >= m_height )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result = true;
|
||||
decode_rle8_bad: ;
|
||||
}
|
||||
break;
|
||||
/************************* 15 BPP ************************/
|
||||
case 15:
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
if( !color )
|
||||
icvCvt_BGR5552Gray_8u_C2C1R( src, 0, data, 0, Size(m_width,1) );
|
||||
else
|
||||
icvCvt_BGR5552BGR_8u_C2C3R( src, 0, data, 0, Size(m_width,1) );
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
/************************* 16 BPP ************************/
|
||||
case 16:
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
if( !color )
|
||||
icvCvt_BGR5652Gray_8u_C2C1R( src, 0, data, 0, Size(m_width,1) );
|
||||
else
|
||||
icvCvt_BGR5652BGR_8u_C2C3R( src, 0, data, 0, Size(m_width,1) );
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
/************************* 24 BPP ************************/
|
||||
case 24:
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
if(!color)
|
||||
icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, Size(m_width,1) );
|
||||
else
|
||||
memcpy( data, src, m_width*3 );
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
/************************* 32 BPP ************************/
|
||||
case 32:
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
|
||||
if( !color )
|
||||
icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, Size(m_width,1) );
|
||||
else if( img.channels() == 3 )
|
||||
icvCvt_BGRA2BGR_8u_C4C3R(src, 0, data, 0, Size(m_width, 1));
|
||||
else if( img.channels() == 4 )
|
||||
memcpy(data, src, m_width * 4);
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
default:
|
||||
CV_Error(cv::Error::StsError, "Invalid/unsupported mode");
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BmpEncoder::BmpEncoder()
|
||||
{
|
||||
m_description = "Windows bitmap (*.bmp;*.dib)";
|
||||
m_buf_supported = true;
|
||||
}
|
||||
|
||||
|
||||
BmpEncoder::~BmpEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
ImageEncoder BmpEncoder::newEncoder() const
|
||||
{
|
||||
return makePtr<BmpEncoder>();
|
||||
}
|
||||
|
||||
bool BmpEncoder::write( const Mat& img, const std::vector<int>& )
|
||||
{
|
||||
int width = img.cols, height = img.rows, channels = img.channels();
|
||||
int fileStep = (width*channels + 3) & -4;
|
||||
uchar zeropad[] = "\0\0\0\0";
|
||||
WLByteStream strm;
|
||||
|
||||
if( m_buf )
|
||||
{
|
||||
if( !strm.open( *m_buf ) )
|
||||
return false;
|
||||
}
|
||||
else if( !strm.open( m_filename ))
|
||||
return false;
|
||||
|
||||
int bitmapHeaderSize = 40;
|
||||
int paletteSize = channels > 1 ? 0 : 1024;
|
||||
int headerSize = 14 /* fileheader */ + bitmapHeaderSize + paletteSize;
|
||||
size_t fileSize = (size_t)fileStep*height + headerSize;
|
||||
PaletteEntry palette[256];
|
||||
|
||||
if( m_buf )
|
||||
m_buf->reserve( alignSize(fileSize + 16, 256) );
|
||||
|
||||
// write signature 'BM'
|
||||
strm.putBytes( fmtSignBmp, (int)strlen(fmtSignBmp) );
|
||||
|
||||
// write file header
|
||||
strm.putDWord( validateToInt(fileSize) ); // file size
|
||||
strm.putDWord( 0 );
|
||||
strm.putDWord( headerSize );
|
||||
|
||||
// write bitmap header
|
||||
strm.putDWord( bitmapHeaderSize );
|
||||
strm.putDWord( width );
|
||||
strm.putDWord( height );
|
||||
strm.putWord( 1 );
|
||||
strm.putWord( channels << 3 );
|
||||
strm.putDWord( BMP_RGB );
|
||||
strm.putDWord( 0 );
|
||||
strm.putDWord( 0 );
|
||||
strm.putDWord( 0 );
|
||||
strm.putDWord( 0 );
|
||||
strm.putDWord( 0 );
|
||||
|
||||
if( channels == 1 )
|
||||
{
|
||||
FillGrayPalette( palette, 8 );
|
||||
strm.putBytes( palette, sizeof(palette));
|
||||
}
|
||||
|
||||
width *= channels;
|
||||
for( int y = height - 1; y >= 0; y-- )
|
||||
{
|
||||
strm.putBytes( img.ptr(y), width );
|
||||
if( fileStep > width )
|
||||
strm.putBytes( zeropad, fileStep - width );
|
||||
}
|
||||
|
||||
strm.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
105
modules/imgcodecs/src/grfmt_bmp.hpp
Normal file
105
modules/imgcodecs/src/grfmt_bmp.hpp
Normal file
@@ -0,0 +1,105 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_BMP_H_
|
||||
#define _GRFMT_BMP_H_
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
enum BmpCompression
|
||||
{
|
||||
BMP_RGB = 0,
|
||||
BMP_RLE8 = 1,
|
||||
BMP_RLE4 = 2,
|
||||
BMP_BITFIELDS = 3
|
||||
};
|
||||
|
||||
|
||||
// Windows Bitmap reader
|
||||
class BmpDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
BmpDecoder();
|
||||
~BmpDecoder() CV_OVERRIDE;
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
void close();
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
enum Origin
|
||||
{
|
||||
ORIGIN_TL = 0,
|
||||
ORIGIN_BL = 1
|
||||
};
|
||||
|
||||
RLByteStream m_strm;
|
||||
PaletteEntry m_palette[256];
|
||||
Origin m_origin;
|
||||
int m_bpp;
|
||||
int m_offset;
|
||||
BmpCompression m_rle_code;
|
||||
};
|
||||
|
||||
|
||||
// ... writer
|
||||
class BmpEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
BmpEncoder();
|
||||
~BmpEncoder() CV_OVERRIDE;
|
||||
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif/*_GRFMT_BMP_H_*/
|
||||
742
modules/imgcodecs/src/grfmt_exr.cpp
Normal file
742
modules/imgcodecs/src/grfmt_exr.cpp
Normal file
@@ -0,0 +1,742 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#ifdef HAVE_OPENEXR
|
||||
|
||||
#if defined _MSC_VER && _MSC_VER >= 1200
|
||||
# pragma warning( disable: 4100 4244 4267 )
|
||||
#endif
|
||||
|
||||
#if defined __GNUC__ && defined __APPLE__
|
||||
# pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
|
||||
/// C++ Standard Libraries
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <ImfHeader.h>
|
||||
#include <ImfInputFile.h>
|
||||
#include <ImfOutputFile.h>
|
||||
#include <ImfChannelList.h>
|
||||
#include <ImfStandardAttributes.h>
|
||||
#include <half.h>
|
||||
#include "grfmt_exr.hpp"
|
||||
|
||||
#if defined _WIN32
|
||||
|
||||
#undef UINT
|
||||
#define UINT ((Imf::PixelType)0)
|
||||
#undef HALF
|
||||
#define HALF ((Imf::PixelType)1)
|
||||
#undef FLOAT
|
||||
#define FLOAT ((Imf::PixelType)2)
|
||||
|
||||
#endif
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/////////////////////// ExrDecoder ///////////////////
|
||||
|
||||
ExrDecoder::ExrDecoder()
|
||||
{
|
||||
m_signature = "\x76\x2f\x31\x01";
|
||||
m_file = 0;
|
||||
m_red = m_green = m_blue = m_alpha = 0;
|
||||
m_type = ((Imf::PixelType)0);
|
||||
m_iscolor = false;
|
||||
m_bit_depth = 0;
|
||||
m_isfloat = false;
|
||||
m_ischroma = false;
|
||||
m_hasalpha = false;
|
||||
m_native_depth = false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
ExrDecoder::~ExrDecoder()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
void ExrDecoder::close()
|
||||
{
|
||||
if( m_file )
|
||||
{
|
||||
delete m_file;
|
||||
m_file = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ExrDecoder::type() const
|
||||
{
|
||||
return CV_MAKETYPE((m_isfloat ? CV_32F : CV_32S), ((m_iscolor && m_hasalpha) ? 4 : m_iscolor ? 3 : m_hasalpha ? 2 : 1));
|
||||
}
|
||||
|
||||
|
||||
bool ExrDecoder::readHeader()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
m_file = new InputFile( m_filename.c_str() );
|
||||
|
||||
if( !m_file ) // probably paranoid
|
||||
return false;
|
||||
|
||||
m_datawindow = m_file->header().dataWindow();
|
||||
m_width = m_datawindow.max.x - m_datawindow.min.x + 1;
|
||||
m_height = m_datawindow.max.y - m_datawindow.min.y + 1;
|
||||
|
||||
// the type HALF is converted to 32 bit float
|
||||
// and the other types supported by OpenEXR are 32 bit anyway
|
||||
m_bit_depth = 32;
|
||||
|
||||
if( hasChromaticities( m_file->header() ))
|
||||
m_chroma = chromaticities( m_file->header() );
|
||||
|
||||
const ChannelList &channels = m_file->header().channels();
|
||||
m_red = channels.findChannel( "R" );
|
||||
m_green = channels.findChannel( "G" );
|
||||
m_blue = channels.findChannel( "B" );
|
||||
m_alpha = channels.findChannel( "A" );
|
||||
|
||||
if( m_alpha ) // alpha channel supported in RGB, Y, and YC scenarios
|
||||
m_hasalpha = true;
|
||||
|
||||
if( m_red || m_green || m_blue )
|
||||
{
|
||||
m_iscolor = true;
|
||||
m_ischroma = false;
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_green = channels.findChannel( "Y" );
|
||||
if( m_green )
|
||||
{
|
||||
m_ischroma = true;
|
||||
m_red = channels.findChannel( "RY" );
|
||||
m_blue = channels.findChannel( "BY" );
|
||||
m_iscolor = (m_blue || m_red);
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
result = false;
|
||||
}
|
||||
|
||||
if( result )
|
||||
{
|
||||
m_type = FLOAT;
|
||||
m_isfloat = ( m_type == FLOAT );
|
||||
}
|
||||
|
||||
if( !result )
|
||||
close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool ExrDecoder::readData( Mat& img )
|
||||
{
|
||||
m_native_depth = CV_MAT_DEPTH(type()) == img.depth();
|
||||
bool color = img.channels() > 2; // output mat has 3+ channels; Y or YA are the 1 and 2 channel scenario
|
||||
bool alphasupported = ( img.channels() % 2 == 0 ); // even number of channels indicates alpha
|
||||
int channels = 0;
|
||||
uchar* data = img.ptr();
|
||||
size_t step = img.step;
|
||||
bool justcopy = ( m_native_depth && (color == m_iscolor) );
|
||||
bool chromatorgb = ( m_ischroma && color );
|
||||
bool rgbtogray = ( !m_ischroma && m_iscolor && !color );
|
||||
bool result = true;
|
||||
FrameBuffer frame;
|
||||
const int defaultchannels = 3;
|
||||
int xsample[defaultchannels] = {1, 1, 1};
|
||||
char *buffer;
|
||||
CV_Assert(m_type == FLOAT);
|
||||
const size_t floatsize = sizeof(float);
|
||||
size_t xstep = m_native_depth ? floatsize : 1; // 4 bytes if native depth (FLOAT), otherwise converting to 1 byte U8 depth
|
||||
size_t ystep = 0;
|
||||
const int channelstoread = ( (m_iscolor && alphasupported) ? 4 :
|
||||
( (m_iscolor && !m_ischroma) || color) ? 3 : alphasupported ? 2 : 1 ); // number of channels to read may exceed channels in output img
|
||||
size_t xStride = floatsize * channelstoread;
|
||||
|
||||
AutoBuffer<char> copy_buffer;
|
||||
|
||||
if( !justcopy )
|
||||
{
|
||||
copy_buffer.allocate(floatsize * m_width * defaultchannels);
|
||||
buffer = copy_buffer.data();
|
||||
ystep = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = (char *)data;
|
||||
ystep = step;
|
||||
}
|
||||
|
||||
if( m_ischroma )
|
||||
{
|
||||
if( color )
|
||||
{
|
||||
if( m_blue )
|
||||
{
|
||||
frame.insert( "BY", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep,
|
||||
xStride, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
|
||||
xsample[0] = m_blue->xSampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "BY", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep,
|
||||
xStride, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
if( m_green )
|
||||
{
|
||||
frame.insert( "Y", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + floatsize,
|
||||
xStride, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
|
||||
xsample[1] = m_green->xSampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "Y", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + floatsize,
|
||||
xStride, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
if( m_red )
|
||||
{
|
||||
frame.insert( "RY", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + (floatsize * 2),
|
||||
xStride, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
|
||||
xsample[2] = m_red->xSampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "RY", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + (floatsize * 2),
|
||||
xStride, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "Y", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep,
|
||||
xStride, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
|
||||
xsample[0] = m_green->xSampling;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_blue )
|
||||
{
|
||||
frame.insert( "B", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep,
|
||||
xStride, ystep, m_blue->xSampling, m_blue->ySampling, 0.0 ));
|
||||
xsample[0] = m_blue->xSampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "B", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep,
|
||||
xStride, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
if( m_green )
|
||||
{
|
||||
frame.insert( "G", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + floatsize,
|
||||
xStride, ystep, m_green->xSampling, m_green->ySampling, 0.0 ));
|
||||
xsample[1] = m_green->xSampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "G", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + floatsize,
|
||||
xStride, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
if( m_red )
|
||||
{
|
||||
frame.insert( "R", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + (floatsize * 2),
|
||||
xStride, ystep, m_red->xSampling, m_red->ySampling, 0.0 ));
|
||||
xsample[2] = m_red->xSampling;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.insert( "R", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + (floatsize * 2),
|
||||
xStride, ystep, 1, 1, 0.0 ));
|
||||
}
|
||||
}
|
||||
|
||||
if( justcopy && m_hasalpha && alphasupported )
|
||||
{ // alpha preserved only in justcopy scenario where alpha is desired (alphasupported)
|
||||
// and present in original file (m_hasalpha)
|
||||
CV_Assert(channelstoread == img.channels());
|
||||
int offset = (channelstoread - 1) * floatsize;
|
||||
frame.insert( "A", Slice( m_type,
|
||||
buffer - m_datawindow.min.x * xStride - m_datawindow.min.y * ystep + offset,
|
||||
xStride, ystep, m_alpha->xSampling, m_alpha->ySampling, 0.0 ));
|
||||
}
|
||||
|
||||
for (FrameBuffer::Iterator it = frame.begin(); it != frame.end(); it++) {
|
||||
channels++;
|
||||
}
|
||||
|
||||
CV_Assert(channels == channelstoread);
|
||||
|
||||
if( (channels != channelstoread) || (!justcopy && channels > defaultchannels) )
|
||||
{ // safety checking what ought to be true here
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_file->setFrameBuffer( frame );
|
||||
if( justcopy )
|
||||
{
|
||||
m_file->readPixels( m_datawindow.min.y, m_datawindow.max.y );
|
||||
|
||||
if( m_iscolor )
|
||||
{
|
||||
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
|
||||
UpSample( data, channelstoread, step / xstep, m_blue->xSampling, m_blue->ySampling );
|
||||
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSample( data + xstep, channelstoread, step / xstep, m_green->xSampling, m_green->ySampling );
|
||||
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
|
||||
UpSample( data + 2 * xstep, channelstoread, step / xstep, m_red->xSampling, m_red->ySampling );
|
||||
}
|
||||
else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSample( data, channelstoread, step / xstep, m_green->xSampling, m_green->ySampling );
|
||||
|
||||
if( chromatorgb )
|
||||
ChromaToBGR( (float *)data, m_height, channelstoread, step / xstep );
|
||||
}
|
||||
else
|
||||
{
|
||||
uchar *out = data;
|
||||
int x, y;
|
||||
for( y = m_datawindow.min.y; y <= m_datawindow.max.y; y++ )
|
||||
{
|
||||
m_file->readPixels( y, y );
|
||||
|
||||
for( int i = 0; i < channels; i++ )
|
||||
{
|
||||
if( xsample[i] != 1 )
|
||||
UpSampleX( (float *)buffer + i, channels, xsample[i] );
|
||||
}
|
||||
if( rgbtogray )
|
||||
{
|
||||
RGBToGray( (float *)buffer, (float *)out );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( chromatorgb )
|
||||
ChromaToBGR( (float *)buffer, 1, defaultchannels, step );
|
||||
|
||||
if( m_type == FLOAT )
|
||||
{
|
||||
float *fi = (float *)buffer;
|
||||
for( x = 0; x < m_width * img.channels(); x++)
|
||||
{
|
||||
out[x] = cv::saturate_cast<uchar>(fi[x]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned *ui = (unsigned *)buffer;
|
||||
for( x = 0; x < m_width * img.channels(); x++)
|
||||
{
|
||||
out[x] = cv::saturate_cast<uchar>(ui[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out += step;
|
||||
}
|
||||
if( color )
|
||||
{
|
||||
if( m_blue && (m_blue->xSampling != 1 || m_blue->ySampling != 1) )
|
||||
UpSampleY( data, defaultchannels, step / xstep, m_blue->ySampling );
|
||||
if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSampleY( data + xstep, defaultchannels, step / xstep, m_green->ySampling );
|
||||
if( m_red && (m_red->xSampling != 1 || m_red->ySampling != 1) )
|
||||
UpSampleY( data + 2 * xstep, defaultchannels, step / xstep, m_red->ySampling );
|
||||
}
|
||||
else if( m_green && (m_green->xSampling != 1 || m_green->ySampling != 1) )
|
||||
UpSampleY( data, 1, step / xstep, m_green->ySampling );
|
||||
}
|
||||
|
||||
close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
// on entry pixel values are stored packed in the upper left corner of the image
|
||||
// this functions expands them by duplication to cover the whole image
|
||||
*/
|
||||
void ExrDecoder::UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample )
|
||||
{
|
||||
for( int y = (m_height - 1) / ysample, yre = m_height - ysample; y >= 0; y--, yre -= ysample )
|
||||
{
|
||||
for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )
|
||||
{
|
||||
for( int i = 0; i < ysample; i++ )
|
||||
{
|
||||
for( int n = 0; n < xsample; n++ )
|
||||
{
|
||||
if( !m_native_depth )
|
||||
data[(yre + i) * ystep + (xre + n) * xstep] = data[y * ystep + x * xstep];
|
||||
else if( m_type == FLOAT )
|
||||
((float *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((float *)data)[y * ystep + x * xstep];
|
||||
else
|
||||
((unsigned *)data)[(yre + i) * ystep + (xre + n) * xstep] = ((unsigned *)data)[y * ystep + x * xstep];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
// on entry pixel values are stored packed in the upper left corner of the image
|
||||
// this functions expands them by duplication to cover the whole image
|
||||
*/
|
||||
void ExrDecoder::UpSampleX( float *data, int xstep, int xsample )
|
||||
{
|
||||
for( int x = (m_width - 1) / xsample, xre = m_width - xsample; x >= 0; x--, xre -= xsample )
|
||||
{
|
||||
for( int n = 0; n < xsample; n++ )
|
||||
{
|
||||
if( m_type == FLOAT )
|
||||
((float *)data)[(xre + n) * xstep] = ((float *)data)[x * xstep];
|
||||
else
|
||||
((unsigned *)data)[(xre + n) * xstep] = ((unsigned *)data)[x * xstep];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
// on entry pixel values are stored packed in the upper left corner of the image
|
||||
// this functions expands them by duplication to cover the whole image
|
||||
*/
|
||||
void ExrDecoder::UpSampleY( uchar *data, int xstep, int ystep, int ysample )
|
||||
{
|
||||
for( int y = m_height - ysample, yre = m_height - ysample; y >= 0; y -= ysample, yre -= ysample )
|
||||
{
|
||||
for( int x = 0; x < m_width; x++ )
|
||||
{
|
||||
for( int i = 1; i < ysample; i++ )
|
||||
{
|
||||
if( !m_native_depth )
|
||||
data[(yre + i) * ystep + x * xstep] = data[y * ystep + x * xstep];
|
||||
else if( m_type == FLOAT )
|
||||
((float *)data)[(yre + i) * ystep + x * xstep] = ((float *)data)[y * ystep + x * xstep];
|
||||
else
|
||||
((unsigned *)data)[(yre + i) * ystep + x * xstep] = ((unsigned *)data)[y * ystep + x * xstep];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
// algorithm from ImfRgbaYca.cpp
|
||||
*/
|
||||
void ExrDecoder::ChromaToBGR( float *data, int numlines, int xstep, int ystep )
|
||||
{
|
||||
for( int y = 0; y < numlines; y++ )
|
||||
{
|
||||
for( int x = 0; x < m_width; x++ )
|
||||
{
|
||||
double b, Y, r;
|
||||
if( m_type == FLOAT )
|
||||
{
|
||||
b = data[y * ystep + x * xstep];
|
||||
Y = data[y * ystep + x * xstep + 1];
|
||||
r = data[y * ystep + x * xstep + 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
b = ((unsigned *)data)[y * ystep + x * xstep];
|
||||
Y = ((unsigned *)data)[y * ystep + x * xstep + 1];
|
||||
r = ((unsigned *)data)[y * ystep + x * xstep + 2];
|
||||
}
|
||||
r = (r + 1) * Y;
|
||||
b = (b + 1) * Y;
|
||||
Y = (Y - b * m_chroma.blue[1] - r * m_chroma.red[1]) / m_chroma.green[1];
|
||||
|
||||
if( m_type == FLOAT )
|
||||
{
|
||||
data[y * ystep + x * xstep] = (float)b;
|
||||
data[y * ystep + x * xstep + 1] = (float)Y;
|
||||
data[y * ystep + x * xstep + 2] = (float)r;
|
||||
}
|
||||
else
|
||||
{
|
||||
int t = cvRound(b);
|
||||
((unsigned *)data)[y * ystep + x * xstep + 0] = (unsigned)MAX(t, 0);
|
||||
t = cvRound(Y);
|
||||
((unsigned *)data)[y * ystep + x * xstep + 1] = (unsigned)MAX(t, 0);
|
||||
t = cvRound(r);
|
||||
((unsigned *)data)[y * ystep + x * xstep + 2] = (unsigned)MAX(t, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
// convert one row to gray
|
||||
*/
|
||||
void ExrDecoder::RGBToGray( float *in, float *out )
|
||||
{
|
||||
if( m_type == FLOAT )
|
||||
{
|
||||
if( m_native_depth )
|
||||
{
|
||||
for( int i = 0, n = 0; i < m_width; i++, n += 3 )
|
||||
out[i] = in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
uchar *o = (uchar *)out;
|
||||
for( int i = 0, n = 0; i < m_width; i++, n += 3 )
|
||||
o[i] = (uchar) (in[n] * m_chroma.blue[0] + in[n + 1] * m_chroma.green[0] + in[n + 2] * m_chroma.red[0]);
|
||||
}
|
||||
}
|
||||
else // UINT
|
||||
{
|
||||
if( m_native_depth )
|
||||
{
|
||||
unsigned *ui = (unsigned *)in;
|
||||
for( int i = 0; i < m_width * 3; i++ )
|
||||
ui[i] -= 0x80000000;
|
||||
int *si = (int *)in;
|
||||
for( int i = 0, n = 0; i < m_width; i++, n += 3 )
|
||||
((int *)out)[i] = int(si[n] * m_chroma.blue[0] + si[n + 1] * m_chroma.green[0] + si[n + 2] * m_chroma.red[0]);
|
||||
}
|
||||
else // how to best convert float to uchar?
|
||||
{
|
||||
unsigned *ui = (unsigned *)in;
|
||||
for( int i = 0, n = 0; i < m_width; i++, n += 3 )
|
||||
((uchar *)out)[i] = uchar((ui[n] * m_chroma.blue[0] + ui[n + 1] * m_chroma.green[0] + ui[n + 2] * m_chroma.red[0]) * (256.0 / 4294967296.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ImageDecoder ExrDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<ExrDecoder>();
|
||||
}
|
||||
|
||||
/////////////////////// ExrEncoder ///////////////////
|
||||
|
||||
|
||||
ExrEncoder::ExrEncoder()
|
||||
{
|
||||
m_description = "OpenEXR Image files (*.exr)";
|
||||
}
|
||||
|
||||
|
||||
ExrEncoder::~ExrEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool ExrEncoder::isFormatSupported( int depth ) const
|
||||
{
|
||||
return ( CV_MAT_DEPTH(depth) == CV_32F );
|
||||
}
|
||||
|
||||
|
||||
bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
|
||||
{
|
||||
int width = img.cols, height = img.rows;
|
||||
int depth = img.depth();
|
||||
CV_Assert( depth == CV_32F );
|
||||
int channels = img.channels();
|
||||
bool result = false;
|
||||
Header header( width, height );
|
||||
Imf::PixelType type = FLOAT;
|
||||
|
||||
for( size_t i = 0; i < params.size(); i += 2 )
|
||||
{
|
||||
if( params[i] == CV_IMWRITE_EXR_TYPE )
|
||||
{
|
||||
switch( params[i+1] )
|
||||
{
|
||||
case IMWRITE_EXR_TYPE_HALF:
|
||||
type = HALF;
|
||||
break;
|
||||
case IMWRITE_EXR_TYPE_FLOAT:
|
||||
type = FLOAT;
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "IMWRITE_EXR_TYPE is invalid or not supported");
|
||||
}
|
||||
}
|
||||
if ( params[i] == IMWRITE_EXR_COMPRESSION )
|
||||
{
|
||||
switch ( params[i + 1] )
|
||||
{
|
||||
case IMWRITE_EXR_COMPRESSION_NO:
|
||||
header.compression() = NO_COMPRESSION;
|
||||
break;
|
||||
case IMWRITE_EXR_COMPRESSION_RLE:
|
||||
header.compression() = RLE_COMPRESSION;
|
||||
break;
|
||||
case IMWRITE_EXR_COMPRESSION_ZIPS:
|
||||
header.compression() = ZIPS_COMPRESSION;
|
||||
break;
|
||||
case IMWRITE_EXR_COMPRESSION_ZIP:
|
||||
header.compression() = ZIP_COMPRESSION;
|
||||
break;
|
||||
case IMWRITE_EXR_COMPRESSION_PIZ:
|
||||
header.compression() = PIZ_COMPRESSION;
|
||||
break;
|
||||
case IMWRITE_EXR_COMPRESSION_PXR24:
|
||||
header.compression() = PXR24_COMPRESSION;
|
||||
break;
|
||||
case IMWRITE_EXR_COMPRESSION_B44:
|
||||
header.compression() = B44_COMPRESSION;
|
||||
break;
|
||||
case IMWRITE_EXR_COMPRESSION_B44A:
|
||||
header.compression() = B44A_COMPRESSION;
|
||||
break;
|
||||
case IMWRITE_EXR_COMPRESSION_DWAA:
|
||||
header.compression() = DWAA_COMPRESSION;
|
||||
break;
|
||||
case IMWRITE_EXR_COMPRESSION_DWAB:
|
||||
header.compression() = DWAB_COMPRESSION;
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "IMWRITE_EXR_COMPRESSION is invalid or not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( channels == 3 || channels == 4 )
|
||||
{
|
||||
header.channels().insert( "R", Channel( type ) );
|
||||
header.channels().insert( "G", Channel( type ) );
|
||||
header.channels().insert( "B", Channel( type ) );
|
||||
//printf("bunt\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
header.channels().insert( "Y", Channel( type ) );
|
||||
//printf("gray\n");
|
||||
}
|
||||
|
||||
if( channels % 2 == 0 )
|
||||
{ // even number of channels indicates Alpha
|
||||
header.channels().insert( "A", Channel( type ) );
|
||||
}
|
||||
|
||||
OutputFile file( m_filename.c_str(), header );
|
||||
|
||||
FrameBuffer frame;
|
||||
|
||||
char *buffer;
|
||||
size_t bufferstep;
|
||||
int size;
|
||||
Mat exrMat;
|
||||
if( type == HALF )
|
||||
{
|
||||
convertFp16(img, exrMat);
|
||||
buffer = (char *)const_cast<uchar *>( exrMat.ptr() );
|
||||
bufferstep = exrMat.step;
|
||||
size = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = (char *)const_cast<uchar *>( img.ptr() );
|
||||
bufferstep = img.step;
|
||||
size = 4;
|
||||
}
|
||||
|
||||
if( channels == 3 || channels == 4 )
|
||||
{
|
||||
frame.insert( "B", Slice( type, buffer, size * channels, bufferstep ));
|
||||
frame.insert( "G", Slice( type, buffer + size, size * channels, bufferstep ));
|
||||
frame.insert( "R", Slice( type, buffer + size * 2, size * channels, bufferstep ));
|
||||
}
|
||||
else
|
||||
frame.insert( "Y", Slice( type, buffer, size * channels, bufferstep ));
|
||||
|
||||
if( channels % 2 == 0 )
|
||||
{ // even channel count indicates Alpha channel
|
||||
frame.insert( "A", Slice( type, buffer + size * (channels - 1), size * channels, bufferstep ));
|
||||
}
|
||||
|
||||
file.setFrameBuffer( frame );
|
||||
|
||||
result = true;
|
||||
try
|
||||
{
|
||||
file.writePixels( height );
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ImageEncoder ExrEncoder::newEncoder() const
|
||||
{
|
||||
return makePtr<ExrEncoder>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* End of file. */
|
||||
123
modules/imgcodecs/src/grfmt_exr.hpp
Normal file
123
modules/imgcodecs/src/grfmt_exr.hpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_EXR_H_
|
||||
#define _GRFMT_EXR_H_
|
||||
|
||||
#ifdef HAVE_OPENEXR
|
||||
|
||||
#if defined __GNUC__ && defined __APPLE__
|
||||
# pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
|
||||
#include <ImfChromaticities.h>
|
||||
#include <ImfInputFile.h>
|
||||
#include <ImfChannelList.h>
|
||||
#include <ImathBox.h>
|
||||
#include "grfmt_base.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
using namespace Imf;
|
||||
using namespace Imath;
|
||||
|
||||
/* libpng version only */
|
||||
|
||||
class ExrDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
ExrDecoder();
|
||||
~ExrDecoder() CV_OVERRIDE;
|
||||
|
||||
int type() const CV_OVERRIDE;
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
void close();
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
void UpSample( uchar *data, int xstep, int ystep, int xsample, int ysample );
|
||||
void UpSampleX( float *data, int xstep, int xsample );
|
||||
void UpSampleY( uchar *data, int xstep, int ystep, int ysample );
|
||||
void ChromaToBGR( float *data, int numlines, int xstep, int ystep );
|
||||
void RGBToGray( float *in, float *out );
|
||||
|
||||
InputFile *m_file;
|
||||
Imf::PixelType m_type;
|
||||
Box2i m_datawindow;
|
||||
bool m_ischroma;
|
||||
const Channel *m_red;
|
||||
const Channel *m_green;
|
||||
const Channel *m_blue;
|
||||
const Channel *m_alpha;
|
||||
Chromaticities m_chroma;
|
||||
int m_bit_depth;
|
||||
bool m_native_depth;
|
||||
bool m_iscolor;
|
||||
bool m_isfloat;
|
||||
bool m_hasalpha;
|
||||
|
||||
private:
|
||||
ExrDecoder(const ExrDecoder &); // copy disabled
|
||||
ExrDecoder& operator=(const ExrDecoder &); // assign disabled
|
||||
};
|
||||
|
||||
|
||||
class ExrEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
ExrEncoder();
|
||||
~ExrEncoder() CV_OVERRIDE;
|
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif/*_GRFMT_EXR_H_*/
|
||||
572
modules/imgcodecs/src/grfmt_gdal.cpp
Normal file
572
modules/imgcodecs/src/grfmt_gdal.cpp
Normal file
@@ -0,0 +1,572 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
#include "precomp.hpp"
|
||||
|
||||
// GDAL Macros
|
||||
#include "cvconfig.h"
|
||||
|
||||
#ifdef HAVE_GDAL
|
||||
|
||||
// Our Header
|
||||
#include "grfmt_gdal.hpp"
|
||||
|
||||
|
||||
/// C++ Standard Libraries
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace cv{
|
||||
|
||||
|
||||
/**
|
||||
* Convert GDAL Palette Interpretation to OpenCV Pixel Type
|
||||
*/
|
||||
int gdalPaletteInterpretation2OpenCV( GDALPaletteInterp const& paletteInterp, GDALDataType const& gdalType ){
|
||||
|
||||
switch( paletteInterp ){
|
||||
|
||||
/// GRAYSCALE
|
||||
case GPI_Gray:
|
||||
if( gdalType == GDT_Byte ){ return CV_8UC1; }
|
||||
if( gdalType == GDT_UInt16 ){ return CV_16UC1; }
|
||||
if( gdalType == GDT_Int16 ){ return CV_16SC1; }
|
||||
if( gdalType == GDT_UInt32 ){ return CV_32SC1; }
|
||||
if( gdalType == GDT_Int32 ){ return CV_32SC1; }
|
||||
if( gdalType == GDT_Float32 ){ return CV_32FC1; }
|
||||
if( gdalType == GDT_Float64 ){ return CV_64FC1; }
|
||||
return -1;
|
||||
|
||||
/// RGB
|
||||
case GPI_RGB:
|
||||
if( gdalType == GDT_Byte ){ return CV_8UC3; }
|
||||
if( gdalType == GDT_UInt16 ){ return CV_16UC3; }
|
||||
if( gdalType == GDT_Int16 ){ return CV_16SC3; }
|
||||
if( gdalType == GDT_UInt32 ){ return CV_32SC3; }
|
||||
if( gdalType == GDT_Int32 ){ return CV_32SC3; }
|
||||
if( gdalType == GDT_Float32 ){ return CV_32FC3; }
|
||||
if( gdalType == GDT_Float64 ){ return CV_64FC3; }
|
||||
return -1;
|
||||
|
||||
|
||||
/// otherwise
|
||||
default:
|
||||
return -1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert gdal type to opencv type
|
||||
*/
|
||||
int gdal2opencv( const GDALDataType& gdalType, const int& channels ){
|
||||
|
||||
switch( gdalType ){
|
||||
|
||||
/// UInt8
|
||||
case GDT_Byte:
|
||||
return CV_8UC(channels);
|
||||
|
||||
/// UInt16
|
||||
case GDT_UInt16:
|
||||
return CV_16UC(channels);
|
||||
|
||||
/// Int16
|
||||
case GDT_Int16:
|
||||
return CV_16SC(channels);
|
||||
|
||||
/// UInt32
|
||||
case GDT_UInt32:
|
||||
case GDT_Int32:
|
||||
return CV_32SC(channels);
|
||||
|
||||
case GDT_Float32:
|
||||
return CV_32FC(channels);
|
||||
|
||||
case GDT_Float64:
|
||||
return CV_64FC(channels);
|
||||
|
||||
default:
|
||||
std::cout << "Unknown GDAL Data Type" << std::endl;
|
||||
std::cout << "Type: " << GDALGetDataTypeName(gdalType) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GDAL Decoder Constructor
|
||||
*/
|
||||
GdalDecoder::GdalDecoder(){
|
||||
|
||||
// set a dummy signature
|
||||
m_signature="0";
|
||||
for( size_t i=0; i<160; i++ ){
|
||||
m_signature += "0";
|
||||
}
|
||||
|
||||
/// Register the driver
|
||||
GDALAllRegister();
|
||||
|
||||
m_driver = NULL;
|
||||
m_dataset = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* GDAL Decoder Destructor
|
||||
*/
|
||||
GdalDecoder::~GdalDecoder(){
|
||||
|
||||
if( m_dataset != NULL ){
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert data range
|
||||
*/
|
||||
double range_cast( const GDALDataType& gdalType,
|
||||
const int& cvDepth,
|
||||
const double& value )
|
||||
{
|
||||
|
||||
// uint8 -> uint8
|
||||
if( gdalType == GDT_Byte && cvDepth == CV_8U ){
|
||||
return value;
|
||||
}
|
||||
// uint8 -> uint16
|
||||
if( gdalType == GDT_Byte && (cvDepth == CV_16U || cvDepth == CV_16S)){
|
||||
return (value*256);
|
||||
}
|
||||
|
||||
// uint8 -> uint32
|
||||
if( gdalType == GDT_Byte && (cvDepth == CV_32F || cvDepth == CV_32S)){
|
||||
return (value*16777216);
|
||||
}
|
||||
|
||||
// int16 -> uint8
|
||||
if( (gdalType == GDT_UInt16 || gdalType == GDT_Int16) && cvDepth == CV_8U ){
|
||||
return std::floor(value/256.0);
|
||||
}
|
||||
|
||||
// int16 -> int16
|
||||
if( (gdalType == GDT_UInt16 || gdalType == GDT_Int16) &&
|
||||
( cvDepth == CV_16U || cvDepth == CV_16S )){
|
||||
return value;
|
||||
}
|
||||
|
||||
// float32 -> float32
|
||||
// float64 -> float64
|
||||
if( (gdalType == GDT_Float32 || gdalType == GDT_Float64) &&
|
||||
( cvDepth == CV_32F || cvDepth == CV_64F )){
|
||||
return value;
|
||||
}
|
||||
|
||||
std::cout << GDALGetDataTypeName( gdalType ) << std::endl;
|
||||
std::cout << "warning: unknown range cast requested." << std::endl;
|
||||
return (value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* There are some better mpl techniques for doing this.
|
||||
*/
|
||||
void write_pixel( const double& pixelValue,
|
||||
const GDALDataType& gdalType,
|
||||
const int& gdalChannels,
|
||||
Mat& image,
|
||||
const int& row,
|
||||
const int& col,
|
||||
const int& channel ){
|
||||
|
||||
// convert the pixel
|
||||
double newValue = range_cast(gdalType, image.depth(), pixelValue );
|
||||
|
||||
// input: 1 channel, output: 1 channel
|
||||
if( gdalChannels == 1 && image.channels() == 1 ){
|
||||
if( image.depth() == CV_8U ){ image.ptr<uchar>(row)[col] = newValue; }
|
||||
else if( image.depth() == CV_16U ){ image.ptr<unsigned short>(row)[col] = newValue; }
|
||||
else if( image.depth() == CV_16S ){ image.ptr<short>(row)[col] = newValue; }
|
||||
else if( image.depth() == CV_32S ){ image.ptr<int>(row)[col] = newValue; }
|
||||
else if( image.depth() == CV_32F ){ image.ptr<float>(row)[col] = newValue; }
|
||||
else if( image.depth() == CV_64F ){ image.ptr<double>(row)[col] = newValue; }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal: 1, img: 1"); }
|
||||
}
|
||||
|
||||
// input: 1 channel, output: 3 channel
|
||||
else if( gdalChannels == 1 && image.channels() == 3 ){
|
||||
if( image.depth() == CV_8U ){ image.ptr<Vec3b>(row)[col] = Vec3b(newValue,newValue,newValue); }
|
||||
else if( image.depth() == CV_16U ){ image.ptr<Vec3s>(row)[col] = Vec3s(newValue,newValue,newValue); }
|
||||
else if( image.depth() == CV_16S ){ image.ptr<Vec3s>(row)[col] = Vec3s(newValue,newValue,newValue); }
|
||||
else if( image.depth() == CV_32S ){ image.ptr<Vec3i>(row)[col] = Vec3i(newValue,newValue,newValue); }
|
||||
else if( image.depth() == CV_32F ){ image.ptr<Vec3f>(row)[col] = Vec3f(newValue,newValue,newValue); }
|
||||
else if( image.depth() == CV_64F ){ image.ptr<Vec3d>(row)[col] = Vec3d(newValue,newValue,newValue); }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal:1, img: 3"); }
|
||||
}
|
||||
|
||||
// input: 3 channel, output: 1 channel
|
||||
else if( gdalChannels == 3 && image.channels() == 1 ){
|
||||
if( image.depth() == CV_8U ){ image.ptr<uchar>(row)[col] += (newValue/3.0); }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal:3, img: 1"); }
|
||||
}
|
||||
|
||||
// input: 4 channel, output: 1 channel
|
||||
else if( gdalChannels == 4 && image.channels() == 1 ){
|
||||
if( image.depth() == CV_8U ){ image.ptr<uchar>(row)[col] = newValue; }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 1"); }
|
||||
}
|
||||
|
||||
// input: 3 channel, output: 3 channel
|
||||
else if( gdalChannels == 3 && image.channels() == 3 ){
|
||||
if( image.depth() == CV_8U ){ (*image.ptr<Vec3b>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16U ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16S ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32S ){ (*image.ptr<Vec3i>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32F ){ (*image.ptr<Vec3f>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_64F ){ (*image.ptr<Vec3d>(row,col))[channel] = newValue; }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal: 3, image: 3"); }
|
||||
}
|
||||
|
||||
// input: 4 channel, output: 3 channel
|
||||
else if( gdalChannels == 4 && image.channels() == 3 ){
|
||||
if( channel >= 4 ){ return; }
|
||||
else if( image.depth() == CV_8U && channel < 4 ){ (*image.ptr<Vec3b>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16U && channel < 4 ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16S && channel < 4 ){ (*image.ptr<Vec3s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32S && channel < 4 ){ (*image.ptr<Vec3i>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32F && channel < 4 ){ (*image.ptr<Vec3f>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_64F && channel < 4 ){ (*image.ptr<Vec3d>(row,col))[channel] = newValue; }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 3"); }
|
||||
}
|
||||
|
||||
// input: 4 channel, output: 4 channel
|
||||
else if( gdalChannels == 4 && image.channels() == 4 ){
|
||||
if( image.depth() == CV_8U ){ (*image.ptr<Vec4b>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16U ){ (*image.ptr<Vec4s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_16S ){ (*image.ptr<Vec4s>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32S ){ (*image.ptr<Vec4i>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_32F ){ (*image.ptr<Vec4f>(row,col))[channel] = newValue; }
|
||||
else if( image.depth() == CV_64F ){ (*image.ptr<Vec4d>(row,col))[channel] = newValue; }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal: 4, image: 4"); }
|
||||
}
|
||||
|
||||
// input: > 4 channels, output: > 4 channels
|
||||
else if( gdalChannels > 4 && image.channels() > 4 ){
|
||||
if( image.depth() == CV_8U ){ image.ptr<uchar>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_16U ){ image.ptr<unsigned short>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_16S ){ image.ptr<short>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_32S ){ image.ptr<int>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_32F ){ image.ptr<float>(row,col)[channel] = newValue; }
|
||||
else if( image.depth() == CV_64F ){ image.ptr<double>(row,col)[channel] = newValue; }
|
||||
else{ throw std::runtime_error("Unknown image depth, gdal: N, img: N"); }
|
||||
}
|
||||
// otherwise, throw an error
|
||||
else{
|
||||
throw std::runtime_error("error: can't convert types.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void write_ctable_pixel( const double& pixelValue,
|
||||
const GDALDataType& gdalType,
|
||||
GDALColorTable const* gdalColorTable,
|
||||
Mat& image,
|
||||
const int& y,
|
||||
const int& x,
|
||||
const int& c ){
|
||||
|
||||
if( gdalColorTable == NULL ){
|
||||
write_pixel( pixelValue, gdalType, 1, image, y, x, c );
|
||||
}
|
||||
|
||||
// if we are Grayscale, then do a straight conversion
|
||||
if( gdalColorTable->GetPaletteInterpretation() == GPI_Gray ){
|
||||
write_pixel( pixelValue, gdalType, 1, image, y, x, c );
|
||||
}
|
||||
|
||||
// if we are rgb, then convert here
|
||||
else if( gdalColorTable->GetPaletteInterpretation() == GPI_RGB ){
|
||||
|
||||
// get the pixel
|
||||
short r = gdalColorTable->GetColorEntry( (int)pixelValue )->c1;
|
||||
short g = gdalColorTable->GetColorEntry( (int)pixelValue )->c2;
|
||||
short b = gdalColorTable->GetColorEntry( (int)pixelValue )->c3;
|
||||
short a = gdalColorTable->GetColorEntry( (int)pixelValue )->c4;
|
||||
|
||||
write_pixel( r, gdalType, 4, image, y, x, 2 );
|
||||
write_pixel( g, gdalType, 4, image, y, x, 1 );
|
||||
write_pixel( b, gdalType, 4, image, y, x, 0 );
|
||||
if( image.channels() > 3 ){
|
||||
write_pixel( a, gdalType, 4, image, y, x, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, set zeros
|
||||
else{
|
||||
write_pixel( pixelValue, gdalType, 1, image, y, x, c );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* read data
|
||||
*/
|
||||
bool GdalDecoder::readData( Mat& img ){
|
||||
|
||||
|
||||
// make sure the image is the proper size
|
||||
if( img.size() != Size(m_width, m_height) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure the raster is alive
|
||||
if( m_dataset == NULL || m_driver == NULL ){
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the image to zero
|
||||
img = 0;
|
||||
|
||||
// iterate over each raster band
|
||||
// note that OpenCV does bgr rather than rgb
|
||||
int nChannels = m_dataset->GetRasterCount();
|
||||
|
||||
GDALColorTable* gdalColorTable = NULL;
|
||||
if( m_dataset->GetRasterBand(1)->GetColorTable() != NULL ){
|
||||
gdalColorTable = m_dataset->GetRasterBand(1)->GetColorTable();
|
||||
}
|
||||
|
||||
const GDALDataType gdalType = m_dataset->GetRasterBand(1)->GetRasterDataType();
|
||||
int nRows, nCols;
|
||||
|
||||
if( nChannels > img.channels() ){
|
||||
nChannels = img.channels();
|
||||
}
|
||||
|
||||
for( int c = 0; c<nChannels; c++ ){
|
||||
|
||||
// get the GDAL Band
|
||||
GDALRasterBand* band = m_dataset->GetRasterBand(c+1);
|
||||
|
||||
/* Map palette band and gray band to color index 0 and red, green,
|
||||
blue, alpha bands to BGRA indexes. Note: ignoring HSL, CMY,
|
||||
CMYK, and YCbCr color spaces, rather than converting them
|
||||
to BGR. */
|
||||
int color = 0;
|
||||
switch (band->GetColorInterpretation()) {
|
||||
case GCI_PaletteIndex:
|
||||
case GCI_GrayIndex:
|
||||
case GCI_BlueBand:
|
||||
color = 0;
|
||||
break;
|
||||
case GCI_GreenBand:
|
||||
color = 1;
|
||||
break;
|
||||
case GCI_RedBand:
|
||||
color = 2;
|
||||
break;
|
||||
case GCI_AlphaBand:
|
||||
color = 3;
|
||||
break;
|
||||
default:
|
||||
CV_Error(cv::Error::StsError, "Invalid/unsupported mode");
|
||||
}
|
||||
|
||||
// make sure the image band has the same dimensions as the image
|
||||
if( band->GetXSize() != m_width || band->GetYSize() != m_height ){ return false; }
|
||||
|
||||
// grab the raster size
|
||||
nRows = band->GetYSize();
|
||||
nCols = band->GetXSize();
|
||||
|
||||
// create a temporary scanline pointer to store data
|
||||
double* scanline = new double[nCols];
|
||||
|
||||
// iterate over each row and column
|
||||
for( int y=0; y<nRows; y++ ){
|
||||
|
||||
// get the entire row
|
||||
CPLErr err = band->RasterIO( GF_Read, 0, y, nCols, 1, scanline, nCols, 1, GDT_Float64, 0, 0);
|
||||
CV_Assert(err == CE_None);
|
||||
|
||||
// set inside the image
|
||||
for( int x=0; x<nCols; x++ ){
|
||||
|
||||
// set depending on image types
|
||||
// given boost, I would use enable_if to speed up. Avoid for now.
|
||||
if( hasColorTable == false ){
|
||||
write_pixel( scanline[x], gdalType, nChannels, img, y, x, color );
|
||||
}
|
||||
else{
|
||||
write_ctable_pixel( scanline[x], gdalType, gdalColorTable, img, y, x, color );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete our temp pointer
|
||||
delete [] scanline;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read image header
|
||||
*/
|
||||
bool GdalDecoder::readHeader(){
|
||||
|
||||
// load the dataset
|
||||
m_dataset = (GDALDataset*) GDALOpen( m_filename.c_str(), GA_ReadOnly);
|
||||
|
||||
// if dataset is null, then there was a problem
|
||||
if( m_dataset == NULL ){
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure we have pixel data inside the raster
|
||||
if( m_dataset->GetRasterCount() <= 0 ){
|
||||
return false;
|
||||
}
|
||||
|
||||
//extract the driver information
|
||||
m_driver = m_dataset->GetDriver();
|
||||
|
||||
// if the driver failed, then exit
|
||||
if( m_driver == NULL ){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// get the image dimensions
|
||||
m_width = m_dataset->GetRasterXSize();
|
||||
m_height= m_dataset->GetRasterYSize();
|
||||
|
||||
// make sure we have at least one band/channel
|
||||
if( m_dataset->GetRasterCount() <= 0 ){
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if we have a color palette
|
||||
int tempType;
|
||||
if( m_dataset->GetRasterBand(1)->GetColorInterpretation() == GCI_PaletteIndex ){
|
||||
|
||||
// remember that we have a color palette
|
||||
hasColorTable = true;
|
||||
|
||||
// if the color tables does not exist, then we failed
|
||||
if( m_dataset->GetRasterBand(1)->GetColorTable() == NULL ){
|
||||
return false;
|
||||
}
|
||||
|
||||
// otherwise, get the pixeltype
|
||||
else{
|
||||
// convert the palette interpretation to opencv type
|
||||
tempType = gdalPaletteInterpretation2OpenCV( m_dataset->GetRasterBand(1)->GetColorTable()->GetPaletteInterpretation(),
|
||||
m_dataset->GetRasterBand(1)->GetRasterDataType() );
|
||||
|
||||
if( tempType == -1 ){
|
||||
return false;
|
||||
}
|
||||
m_type = tempType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// otherwise, we have standard channels
|
||||
else{
|
||||
|
||||
// remember that we don't have a color table
|
||||
hasColorTable = false;
|
||||
|
||||
// convert the datatype to opencv
|
||||
tempType = gdal2opencv( m_dataset->GetRasterBand(1)->GetRasterDataType(), m_dataset->GetRasterCount() );
|
||||
if( tempType == -1 ){
|
||||
return false;
|
||||
}
|
||||
m_type = tempType;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the module
|
||||
*/
|
||||
void GdalDecoder::close(){
|
||||
|
||||
|
||||
GDALClose((GDALDatasetH)m_dataset);
|
||||
m_dataset = NULL;
|
||||
m_driver = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new decoder
|
||||
*/
|
||||
ImageDecoder GdalDecoder::newDecoder()const{
|
||||
return makePtr<GdalDecoder>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the file signature
|
||||
*/
|
||||
bool GdalDecoder::checkSignature( const String& signature )const{
|
||||
|
||||
// look for NITF
|
||||
std::string str(signature);
|
||||
if( str.substr(0,4).find("NITF") != std::string::npos ){
|
||||
return true;
|
||||
}
|
||||
|
||||
// look for DTED
|
||||
if( str.size() > 144 && str.substr(140,4) == "DTED" ){
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} /// End of cv Namespace
|
||||
|
||||
#endif /**< End of HAVE_GDAL Definition */
|
||||
166
modules/imgcodecs/src/grfmt_gdal.hpp
Normal file
166
modules/imgcodecs/src/grfmt_gdal.hpp
Normal file
@@ -0,0 +1,166 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __GRFMT_GDAL_HPP__
|
||||
#define __GRFMT_GDAL_HPP__
|
||||
|
||||
/// OpenCV FMT Base Type
|
||||
#include "grfmt_base.hpp"
|
||||
|
||||
/// Macro to make sure we specified GDAL in CMake
|
||||
#ifdef HAVE_GDAL
|
||||
|
||||
/// C++ Libraries
|
||||
#include <iostream>
|
||||
|
||||
/// Geospatial Data Abstraction Library
|
||||
#include <cpl_conv.h>
|
||||
#include <gdal_priv.h>
|
||||
#include <gdal.h>
|
||||
|
||||
|
||||
/// Start of CV Namespace
|
||||
namespace cv {
|
||||
|
||||
/**
|
||||
* Convert GDAL Pixel Range to OpenCV Pixel Range
|
||||
*/
|
||||
double range_cast( const GDALDataType& gdalType,
|
||||
const int& cvDepth,
|
||||
const double& value );
|
||||
|
||||
/**
|
||||
* Convert GDAL Palette Interpretation to OpenCV Pixel Type
|
||||
*/
|
||||
int gdalPaletteInterpretation2OpenCV( GDALPaletteInterp const& paletteInterp,
|
||||
GDALDataType const& gdalType );
|
||||
|
||||
/**
|
||||
* Convert a GDAL Raster Type to OpenCV Type
|
||||
*/
|
||||
int gdal2opencv( const GDALDataType& gdalType, const int& channels );
|
||||
|
||||
/**
|
||||
* Write an image to pixel
|
||||
*/
|
||||
void write_pixel( const double& pixelValue,
|
||||
GDALDataType const& gdalType,
|
||||
const int& gdalChannels,
|
||||
Mat& image,
|
||||
const int& row,
|
||||
const int& col,
|
||||
const int& channel );
|
||||
|
||||
/**
|
||||
* Write a color table pixel to the image
|
||||
*/
|
||||
void write_ctable_pixel( const double& pixelValue,
|
||||
const GDALDataType& gdalType,
|
||||
const GDALColorTable* gdalColorTable,
|
||||
Mat& image,
|
||||
const int& y,
|
||||
const int& x,
|
||||
const int& c );
|
||||
|
||||
/**
|
||||
* Loader for GDAL
|
||||
*/
|
||||
class GdalDecoder CV_FINAL : public BaseImageDecoder{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
GdalDecoder();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~GdalDecoder() CV_OVERRIDE;
|
||||
|
||||
/**
|
||||
* Read image data
|
||||
*/
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
|
||||
/**
|
||||
* Read the image header
|
||||
*/
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
|
||||
/**
|
||||
* Close the module
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Create a new decoder
|
||||
*/
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
/**
|
||||
* Test the file signature
|
||||
*
|
||||
* In general, this should be avoided as the user should specifically request GDAL.
|
||||
* The reason is that GDAL tends to overlap with other image formats and it is probably
|
||||
* safer to use other formats first.
|
||||
*/
|
||||
virtual bool checkSignature( const String& signature ) const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
/// GDAL Dataset
|
||||
GDALDataset* m_dataset;
|
||||
|
||||
/// GDAL Driver
|
||||
GDALDriver* m_driver;
|
||||
|
||||
/// Check if we are reading from a color table
|
||||
bool hasColorTable;
|
||||
|
||||
}; /// End of GdalDecoder Class
|
||||
|
||||
} /// End of Namespace cv
|
||||
|
||||
#endif/*HAVE_GDAL*/
|
||||
|
||||
#endif/*__GRFMT_GDAL_HPP__*/
|
||||
197
modules/imgcodecs/src/grfmt_gdcm.cpp
Normal file
197
modules/imgcodecs/src/grfmt_gdcm.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "grfmt_gdcm.hpp"
|
||||
|
||||
#ifdef HAVE_GDCM
|
||||
|
||||
//#define DBG(...) printf(__VA_ARGS__)
|
||||
#define DBG(...)
|
||||
|
||||
#include <gdcmImageReader.h>
|
||||
|
||||
static const size_t preamble_skip = 128;
|
||||
static const size_t magic_len = 4;
|
||||
|
||||
inline cv::String getMagic()
|
||||
{
|
||||
return cv::String("\x44\x49\x43\x4D", 4);
|
||||
}
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/************************ DICOM decoder *****************************/
|
||||
|
||||
DICOMDecoder::DICOMDecoder()
|
||||
{
|
||||
// DICOM preamble is 128 bytes (can have any value, defaults to 0) + 4 bytes magic number (DICM)
|
||||
m_signature = String(preamble_skip, (char)'\x0') + getMagic();
|
||||
m_buf_supported = false;
|
||||
}
|
||||
|
||||
bool DICOMDecoder::checkSignature( const String& signature ) const
|
||||
{
|
||||
if (signature.size() >= preamble_skip + magic_len)
|
||||
{
|
||||
if (signature.substr(preamble_skip, magic_len) == getMagic())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
DBG("GDCM | Signature does not match\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageDecoder DICOMDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<DICOMDecoder>();
|
||||
}
|
||||
|
||||
bool DICOMDecoder::readHeader()
|
||||
{
|
||||
gdcm::ImageReader csImageReader;
|
||||
csImageReader.SetFileName(m_filename.c_str());
|
||||
if(!csImageReader.Read())
|
||||
{
|
||||
DBG("GDCM | Failed to open DICOM file\n");
|
||||
return(false);
|
||||
}
|
||||
|
||||
const gdcm::Image &csImage = csImageReader.GetImage();
|
||||
bool bOK = true;
|
||||
switch (csImage.GetPhotometricInterpretation().GetType())
|
||||
{
|
||||
case gdcm::PhotometricInterpretation::MONOCHROME1:
|
||||
case gdcm::PhotometricInterpretation::MONOCHROME2:
|
||||
{
|
||||
switch (csImage.GetPixelFormat().GetScalarType())
|
||||
{
|
||||
case gdcm::PixelFormat::INT8: m_type = CV_8SC1; break;
|
||||
case gdcm::PixelFormat::UINT8: m_type = CV_8UC1; break;
|
||||
case gdcm::PixelFormat::INT16: m_type = CV_16SC1; break;
|
||||
case gdcm::PixelFormat::UINT16: m_type = CV_16UC1; break;
|
||||
case gdcm::PixelFormat::INT32: m_type = CV_32SC1; break;
|
||||
case gdcm::PixelFormat::FLOAT32: m_type = CV_32FC1; break;
|
||||
case gdcm::PixelFormat::FLOAT64: m_type = CV_64FC1; break;
|
||||
default: bOK = false; DBG("GDCM | Monochrome scalar type not supported\n"); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case gdcm::PhotometricInterpretation::RGB:
|
||||
{
|
||||
switch (csImage.GetPixelFormat().GetScalarType())
|
||||
{
|
||||
case gdcm::PixelFormat::UINT8: m_type = CV_8UC3; break;
|
||||
default: bOK = false; DBG("GDCM | RGB scalar type not supported\n"); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
bOK = false;
|
||||
DBG("GDCM | PI not supported: %s\n", csImage.GetPhotometricInterpretation().GetString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(bOK)
|
||||
{
|
||||
unsigned int ndim = csImage.GetNumberOfDimensions();
|
||||
if (ndim != 2)
|
||||
{
|
||||
DBG("GDCM | Invalid dimensions number: %d\n", ndim);
|
||||
bOK = false;
|
||||
}
|
||||
}
|
||||
if (bOK)
|
||||
{
|
||||
const unsigned int *piDimension = csImage.GetDimensions();
|
||||
m_height = piDimension[0];
|
||||
m_width = piDimension[1];
|
||||
if( ( m_width <=0 ) || ( m_height <=0 ) )
|
||||
{
|
||||
DBG("GDCM | Invalid dimensions: %d x %d\n", piDimension[0], piDimension[1]);
|
||||
bOK = false;
|
||||
}
|
||||
}
|
||||
|
||||
return(bOK);
|
||||
}
|
||||
|
||||
|
||||
bool DICOMDecoder::readData( Mat& csImage )
|
||||
{
|
||||
csImage.create(m_width,m_height,m_type);
|
||||
|
||||
gdcm::ImageReader csImageReader;
|
||||
csImageReader.SetFileName(m_filename.c_str());
|
||||
if(!csImageReader.Read())
|
||||
{
|
||||
DBG("GDCM | Failed to Read\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const gdcm::Image &img = csImageReader.GetImage();
|
||||
|
||||
unsigned long len = img.GetBufferLength();
|
||||
if (len > csImage.elemSize() * csImage.total())
|
||||
{
|
||||
DBG("GDCM | Buffer is bigger than Mat: %ld > %ld * %ld\n", len, csImage.elemSize(), csImage.total());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!img.GetBuffer((char*)csImage.ptr()))
|
||||
{
|
||||
DBG("GDCM | Failed to GetBuffer\n");
|
||||
return false;
|
||||
}
|
||||
DBG("GDCM | Read OK\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_GDCM
|
||||
70
modules/imgcodecs/src/grfmt_gdcm.hpp
Normal file
70
modules/imgcodecs/src/grfmt_gdcm.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GDCM_DICOM_H_
|
||||
#define _GDCM_DICOM_H_
|
||||
|
||||
#include "cvconfig.h"
|
||||
|
||||
#ifdef HAVE_GDCM
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
// DICOM image reader using GDCM
|
||||
class DICOMDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
DICOMDecoder();
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
virtual bool checkSignature( const String& signature ) const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_GDCM
|
||||
|
||||
#endif/*_GDCM_DICOM_H_*/
|
||||
172
modules/imgcodecs/src/grfmt_hdr.cpp
Normal file
172
modules/imgcodecs/src/grfmt_hdr.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "grfmt_hdr.hpp"
|
||||
#include "rgbe.hpp"
|
||||
|
||||
#ifdef HAVE_IMGCODEC_HDR
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
HdrDecoder::HdrDecoder()
|
||||
{
|
||||
m_signature = "#?RGBE";
|
||||
m_signature_alt = "#?RADIANCE";
|
||||
file = NULL;
|
||||
m_type = CV_32FC3;
|
||||
}
|
||||
|
||||
HdrDecoder::~HdrDecoder()
|
||||
{
|
||||
}
|
||||
|
||||
size_t HdrDecoder::signatureLength() const
|
||||
{
|
||||
return m_signature.size() > m_signature_alt.size() ?
|
||||
m_signature.size() : m_signature_alt.size();
|
||||
}
|
||||
|
||||
bool HdrDecoder::readHeader()
|
||||
{
|
||||
file = fopen(m_filename.c_str(), "rb");
|
||||
if(!file) {
|
||||
return false;
|
||||
}
|
||||
RGBE_ReadHeader(file, &m_width, &m_height, NULL);
|
||||
if(m_width <= 0 || m_height <= 0) {
|
||||
fclose(file);
|
||||
file = NULL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HdrDecoder::readData(Mat& _img)
|
||||
{
|
||||
Mat img(m_height, m_width, CV_32FC3);
|
||||
if(!file) {
|
||||
if(!readHeader()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
RGBE_ReadPixels_RLE(file, const_cast<float*>(img.ptr<float>()), img.cols, img.rows);
|
||||
fclose(file); file = NULL;
|
||||
|
||||
if(_img.depth() == img.depth()) {
|
||||
img.convertTo(_img, _img.type());
|
||||
} else {
|
||||
img.convertTo(_img, _img.type(), 255);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HdrDecoder::checkSignature( const String& signature ) const
|
||||
{
|
||||
if (signature.size() >= m_signature.size() &&
|
||||
0 == memcmp(signature.c_str(), m_signature.c_str(), m_signature.size())
|
||||
)
|
||||
return true;
|
||||
if (signature.size() >= m_signature_alt.size() &&
|
||||
0 == memcmp(signature.c_str(), m_signature_alt.c_str(), m_signature_alt.size())
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageDecoder HdrDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<HdrDecoder>();
|
||||
}
|
||||
|
||||
HdrEncoder::HdrEncoder()
|
||||
{
|
||||
m_description = "Radiance HDR (*.hdr;*.pic)";
|
||||
}
|
||||
|
||||
HdrEncoder::~HdrEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
bool HdrEncoder::write( const Mat& input_img, const std::vector<int>& params )
|
||||
{
|
||||
Mat img;
|
||||
CV_Assert(input_img.channels() == 3 || input_img.channels() == 1);
|
||||
if(input_img.channels() == 1) {
|
||||
std::vector<Mat> splitted(3, input_img);
|
||||
merge(splitted, img);
|
||||
} else {
|
||||
input_img.copyTo(img);
|
||||
}
|
||||
if(img.depth() != CV_32F) {
|
||||
img.convertTo(img, CV_32FC3, 1/255.0f);
|
||||
}
|
||||
CV_Assert(params.empty() || params[0] == HDR_NONE || params[0] == HDR_RLE);
|
||||
FILE *fout = fopen(m_filename.c_str(), "wb");
|
||||
if(!fout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RGBE_WriteHeader(fout, img.cols, img.rows, NULL);
|
||||
if(params.empty() || params[0] == HDR_RLE) {
|
||||
RGBE_WritePixels_RLE(fout, const_cast<float*>(img.ptr<float>()), img.cols, img.rows);
|
||||
} else {
|
||||
RGBE_WritePixels(fout, const_cast<float*>(img.ptr<float>()), img.cols * img.rows);
|
||||
}
|
||||
|
||||
fclose(fout);
|
||||
return true;
|
||||
}
|
||||
|
||||
ImageEncoder HdrEncoder::newEncoder() const
|
||||
{
|
||||
return makePtr<HdrEncoder>();
|
||||
}
|
||||
|
||||
bool HdrEncoder::isFormatSupported( int depth ) const {
|
||||
return depth != CV_64F;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_IMGCODEC_HDR
|
||||
92
modules/imgcodecs/src/grfmt_hdr.hpp
Normal file
92
modules/imgcodecs/src/grfmt_hdr.hpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_HDR_H_
|
||||
#define _GRFMT_HDR_H_
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
|
||||
#ifdef HAVE_IMGCODEC_HDR
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
enum HdrCompression
|
||||
{
|
||||
HDR_NONE = 0,
|
||||
HDR_RLE = 1
|
||||
};
|
||||
|
||||
// Radiance rgbe (.hdr) reader
|
||||
class HdrDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
HdrDecoder();
|
||||
~HdrDecoder() CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool checkSignature( const String& signature ) const CV_OVERRIDE;
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
size_t signatureLength() const CV_OVERRIDE;
|
||||
protected:
|
||||
String m_signature_alt;
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
// ... writer
|
||||
class HdrEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
HdrEncoder();
|
||||
~HdrEncoder() CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_IMGCODEC_HDR
|
||||
|
||||
#endif/*_GRFMT_HDR_H_*/
|
||||
765
modules/imgcodecs/src/grfmt_jpeg.cpp
Normal file
765
modules/imgcodecs/src/grfmt_jpeg.cpp
Normal file
@@ -0,0 +1,765 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "grfmt_jpeg.hpp"
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
|
||||
#ifdef _MSC_VER
|
||||
//interaction between '_setjmp' and C++ object destruction is non-portable
|
||||
#pragma warning(disable: 4611)
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
// the following defines are a hack to avoid multiple problems with frame pointer handling and setjmp
|
||||
// see http://gcc.gnu.org/ml/gcc/2011-10/msg00324.html for some details
|
||||
#define mingw_getsp(...) 0
|
||||
#define __builtin_frame_address(...) 0
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define XMD_H // prevent redefinition of INT32
|
||||
#undef FAR // prevent FAR redefinition
|
||||
|
||||
#endif
|
||||
|
||||
#if defined _WIN32 && defined __GNUC__
|
||||
typedef unsigned char boolean;
|
||||
#endif
|
||||
|
||||
#undef FALSE
|
||||
#undef TRUE
|
||||
|
||||
extern "C" {
|
||||
#include "jpeglib.h"
|
||||
}
|
||||
|
||||
#ifndef CV_MANUAL_JPEG_STD_HUFF_TABLES
|
||||
#if defined(LIBJPEG_TURBO_VERSION_NUMBER) && LIBJPEG_TURBO_VERSION_NUMBER >= 1003090
|
||||
#define CV_MANUAL_JPEG_STD_HUFF_TABLES 0 // libjpeg-turbo handles standard huffman tables itself (jstdhuff.c)
|
||||
#else
|
||||
#define CV_MANUAL_JPEG_STD_HUFF_TABLES 1
|
||||
#endif
|
||||
#endif
|
||||
#if CV_MANUAL_JPEG_STD_HUFF_TABLES == 0
|
||||
#undef CV_MANUAL_JPEG_STD_HUFF_TABLES
|
||||
#endif
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
struct JpegErrorMgr
|
||||
{
|
||||
struct jpeg_error_mgr pub;
|
||||
jmp_buf setjmp_buffer;
|
||||
};
|
||||
|
||||
struct JpegSource
|
||||
{
|
||||
struct jpeg_source_mgr pub;
|
||||
int skip;
|
||||
};
|
||||
|
||||
struct JpegState
|
||||
{
|
||||
jpeg_decompress_struct cinfo; // IJG JPEG codec structure
|
||||
JpegErrorMgr jerr; // error processing manager state
|
||||
JpegSource source; // memory buffer source
|
||||
};
|
||||
|
||||
/////////////////////// Error processing /////////////////////
|
||||
|
||||
METHODDEF(void)
|
||||
stub(j_decompress_ptr)
|
||||
{
|
||||
}
|
||||
|
||||
METHODDEF(boolean)
|
||||
fill_input_buffer(j_decompress_ptr)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// emulating memory input stream
|
||||
|
||||
METHODDEF(void)
|
||||
skip_input_data(j_decompress_ptr cinfo, long num_bytes)
|
||||
{
|
||||
JpegSource* source = (JpegSource*) cinfo->src;
|
||||
|
||||
if( num_bytes > (long)source->pub.bytes_in_buffer )
|
||||
{
|
||||
// We need to skip more data than we have in the buffer.
|
||||
// This will force the JPEG library to suspend decoding.
|
||||
source->skip = (int)(num_bytes - source->pub.bytes_in_buffer);
|
||||
source->pub.next_input_byte += source->pub.bytes_in_buffer;
|
||||
source->pub.bytes_in_buffer = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip portion of the buffer
|
||||
source->pub.bytes_in_buffer -= num_bytes;
|
||||
source->pub.next_input_byte += num_bytes;
|
||||
source->skip = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void jpeg_buffer_src(j_decompress_ptr cinfo, JpegSource* source)
|
||||
{
|
||||
cinfo->src = &source->pub;
|
||||
|
||||
// Prepare for suspending reader
|
||||
source->pub.init_source = stub;
|
||||
source->pub.fill_input_buffer = fill_input_buffer;
|
||||
source->pub.skip_input_data = skip_input_data;
|
||||
source->pub.resync_to_restart = jpeg_resync_to_restart;
|
||||
source->pub.term_source = stub;
|
||||
source->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read
|
||||
|
||||
source->skip = 0;
|
||||
}
|
||||
|
||||
|
||||
METHODDEF(void)
|
||||
error_exit( j_common_ptr cinfo )
|
||||
{
|
||||
JpegErrorMgr* err_mgr = (JpegErrorMgr*)(cinfo->err);
|
||||
|
||||
/* Return control to the setjmp point */
|
||||
longjmp( err_mgr->setjmp_buffer, 1 );
|
||||
}
|
||||
|
||||
|
||||
/////////////////////// JpegDecoder ///////////////////
|
||||
|
||||
|
||||
JpegDecoder::JpegDecoder()
|
||||
{
|
||||
m_signature = "\xFF\xD8\xFF";
|
||||
m_state = 0;
|
||||
m_f = 0;
|
||||
m_buf_supported = true;
|
||||
}
|
||||
|
||||
|
||||
JpegDecoder::~JpegDecoder()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
void JpegDecoder::close()
|
||||
{
|
||||
if( m_state )
|
||||
{
|
||||
JpegState* state = (JpegState*)m_state;
|
||||
jpeg_destroy_decompress( &state->cinfo );
|
||||
delete state;
|
||||
m_state = 0;
|
||||
}
|
||||
|
||||
if( m_f )
|
||||
{
|
||||
fclose( m_f );
|
||||
m_f = 0;
|
||||
}
|
||||
|
||||
m_width = m_height = 0;
|
||||
m_type = -1;
|
||||
}
|
||||
|
||||
ImageDecoder JpegDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<JpegDecoder>();
|
||||
}
|
||||
|
||||
bool JpegDecoder::readHeader()
|
||||
{
|
||||
volatile bool result = false;
|
||||
close();
|
||||
|
||||
JpegState* state = new JpegState;
|
||||
m_state = state;
|
||||
state->cinfo.err = jpeg_std_error(&state->jerr.pub);
|
||||
state->jerr.pub.error_exit = error_exit;
|
||||
|
||||
if( setjmp( state->jerr.setjmp_buffer ) == 0 )
|
||||
{
|
||||
jpeg_create_decompress( &state->cinfo );
|
||||
|
||||
if( !m_buf.empty() )
|
||||
{
|
||||
jpeg_buffer_src(&state->cinfo, &state->source);
|
||||
state->source.pub.next_input_byte = m_buf.ptr();
|
||||
state->source.pub.bytes_in_buffer = m_buf.cols*m_buf.rows*m_buf.elemSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_f = fopen( m_filename.c_str(), "rb" );
|
||||
if( m_f )
|
||||
jpeg_stdio_src( &state->cinfo, m_f );
|
||||
}
|
||||
|
||||
if (state->cinfo.src != 0)
|
||||
{
|
||||
jpeg_save_markers(&state->cinfo, APP1, 0xffff);
|
||||
jpeg_read_header( &state->cinfo, TRUE );
|
||||
|
||||
state->cinfo.scale_num=1;
|
||||
state->cinfo.scale_denom = m_scale_denom;
|
||||
m_scale_denom=1; // trick! to know which decoder used scale_denom see imread_
|
||||
jpeg_calc_output_dimensions(&state->cinfo);
|
||||
m_width = state->cinfo.output_width;
|
||||
m_height = state->cinfo.output_height;
|
||||
m_type = state->cinfo.num_components > 1 ? CV_8UC3 : CV_8UC1;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( !result )
|
||||
close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef CV_MANUAL_JPEG_STD_HUFF_TABLES
|
||||
/***************************************************************************
|
||||
* following code is for supporting MJPEG image files
|
||||
* based on a message of Laurent Pinchart on the video4linux mailing list
|
||||
***************************************************************************/
|
||||
|
||||
/* JPEG DHT Segment for YCrCb omitted from MJPEG data */
|
||||
static
|
||||
unsigned char my_jpeg_odml_dht[0x1a4] = {
|
||||
0xff, 0xc4, 0x01, 0xa2,
|
||||
|
||||
0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
|
||||
0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
|
||||
0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
|
||||
0x04, 0x00, 0x00, 0x01, 0x7d,
|
||||
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
|
||||
0x13, 0x51, 0x61, 0x07,
|
||||
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1,
|
||||
0x15, 0x52, 0xd1, 0xf0,
|
||||
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a,
|
||||
0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
|
||||
0x46, 0x47, 0x48, 0x49,
|
||||
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
|
||||
0x66, 0x67, 0x68, 0x69,
|
||||
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85,
|
||||
0x86, 0x87, 0x88, 0x89,
|
||||
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
|
||||
0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
|
||||
0xc2, 0xc3, 0xc4, 0xc5,
|
||||
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
|
||||
0xd9, 0xda, 0xe1, 0xe2,
|
||||
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
|
||||
0xf5, 0xf6, 0xf7, 0xf8,
|
||||
0xf9, 0xfa,
|
||||
|
||||
0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
|
||||
0x04, 0x00, 0x01, 0x02, 0x77,
|
||||
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
|
||||
0x51, 0x07, 0x61, 0x71,
|
||||
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09,
|
||||
0x23, 0x33, 0x52, 0xf0,
|
||||
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x26,
|
||||
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
|
||||
0x45, 0x46, 0x47, 0x48,
|
||||
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
|
||||
0x65, 0x66, 0x67, 0x68,
|
||||
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
|
||||
0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
|
||||
0xa2, 0xa3, 0xa4, 0xa5,
|
||||
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
|
||||
0xb9, 0xba, 0xc2, 0xc3,
|
||||
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
|
||||
0xd7, 0xd8, 0xd9, 0xda,
|
||||
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
|
||||
0xf5, 0xf6, 0xf7, 0xf8,
|
||||
0xf9, 0xfa
|
||||
};
|
||||
|
||||
/*
|
||||
* Parse the DHT table.
|
||||
* This code comes from jpeg6b (jdmarker.c).
|
||||
*/
|
||||
static
|
||||
int my_jpeg_load_dht (struct jpeg_decompress_struct *info, unsigned char *dht,
|
||||
JHUFF_TBL *ac_tables[], JHUFF_TBL *dc_tables[])
|
||||
{
|
||||
unsigned int length = (dht[2] << 8) + dht[3] - 2;
|
||||
unsigned int pos = 4;
|
||||
unsigned int count, i;
|
||||
int index;
|
||||
|
||||
JHUFF_TBL **hufftbl;
|
||||
unsigned char bits[17];
|
||||
unsigned char huffval[256] = {0};
|
||||
|
||||
while (length > 16)
|
||||
{
|
||||
bits[0] = 0;
|
||||
index = dht[pos++];
|
||||
count = 0;
|
||||
for (i = 1; i <= 16; ++i)
|
||||
{
|
||||
bits[i] = dht[pos++];
|
||||
count += bits[i];
|
||||
}
|
||||
length -= 17;
|
||||
|
||||
if (count > 256 || count > length)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
huffval[i] = dht[pos++];
|
||||
length -= count;
|
||||
|
||||
if (index & 0x10)
|
||||
{
|
||||
index &= ~0x10;
|
||||
hufftbl = &ac_tables[index];
|
||||
}
|
||||
else
|
||||
hufftbl = &dc_tables[index];
|
||||
|
||||
if (index < 0 || index >= NUM_HUFF_TBLS)
|
||||
return -1;
|
||||
|
||||
if (*hufftbl == NULL)
|
||||
*hufftbl = jpeg_alloc_huff_table ((j_common_ptr)info);
|
||||
if (*hufftbl == NULL)
|
||||
return -1;
|
||||
|
||||
memcpy ((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits);
|
||||
memcpy ((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval);
|
||||
}
|
||||
|
||||
if (length != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* end of code for supportting MJPEG image files
|
||||
* based on a message of Laurent Pinchart on the video4linux mailing list
|
||||
***************************************************************************/
|
||||
#endif // CV_MANUAL_JPEG_STD_HUFF_TABLES
|
||||
|
||||
bool JpegDecoder::readData( Mat& img )
|
||||
{
|
||||
volatile bool result = false;
|
||||
size_t step = img.step;
|
||||
bool color = img.channels() > 1;
|
||||
|
||||
if( m_state && m_width && m_height )
|
||||
{
|
||||
jpeg_decompress_struct* cinfo = &((JpegState*)m_state)->cinfo;
|
||||
JpegErrorMgr* jerr = &((JpegState*)m_state)->jerr;
|
||||
JSAMPARRAY buffer = 0;
|
||||
|
||||
if( setjmp( jerr->setjmp_buffer ) == 0 )
|
||||
{
|
||||
#ifdef CV_MANUAL_JPEG_STD_HUFF_TABLES
|
||||
/* check if this is a mjpeg image format */
|
||||
if ( cinfo->ac_huff_tbl_ptrs[0] == NULL &&
|
||||
cinfo->ac_huff_tbl_ptrs[1] == NULL &&
|
||||
cinfo->dc_huff_tbl_ptrs[0] == NULL &&
|
||||
cinfo->dc_huff_tbl_ptrs[1] == NULL )
|
||||
{
|
||||
/* yes, this is a mjpeg image format, so load the correct
|
||||
huffman table */
|
||||
my_jpeg_load_dht( cinfo,
|
||||
my_jpeg_odml_dht,
|
||||
cinfo->ac_huff_tbl_ptrs,
|
||||
cinfo->dc_huff_tbl_ptrs );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( color )
|
||||
{
|
||||
if( cinfo->num_components != 4 )
|
||||
{
|
||||
cinfo->out_color_space = JCS_RGB;
|
||||
cinfo->out_color_components = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
cinfo->out_color_space = JCS_CMYK;
|
||||
cinfo->out_color_components = 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( cinfo->num_components != 4 )
|
||||
{
|
||||
cinfo->out_color_space = JCS_GRAYSCALE;
|
||||
cinfo->out_color_components = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cinfo->out_color_space = JCS_CMYK;
|
||||
cinfo->out_color_components = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for Exif marker APP1
|
||||
jpeg_saved_marker_ptr exif_marker = NULL;
|
||||
jpeg_saved_marker_ptr cmarker = cinfo->marker_list;
|
||||
while( cmarker && exif_marker == NULL )
|
||||
{
|
||||
if (cmarker->marker == APP1)
|
||||
exif_marker = cmarker;
|
||||
|
||||
cmarker = cmarker->next;
|
||||
}
|
||||
|
||||
// Parse Exif data
|
||||
if( exif_marker )
|
||||
{
|
||||
const std::streamsize offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header
|
||||
|
||||
if (exif_marker->data_length > offsetToTiffHeader)
|
||||
{
|
||||
m_exif.parseExif(exif_marker->data + offsetToTiffHeader, exif_marker->data_length - offsetToTiffHeader);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jpeg_start_decompress( cinfo );
|
||||
|
||||
buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo,
|
||||
JPOOL_IMAGE, m_width*4, 1 );
|
||||
|
||||
uchar* data = img.ptr();
|
||||
for( ; m_height--; data += step )
|
||||
{
|
||||
jpeg_read_scanlines( cinfo, buffer, 1 );
|
||||
if( color )
|
||||
{
|
||||
if( cinfo->out_color_components == 3 )
|
||||
icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, Size(m_width,1) );
|
||||
else
|
||||
icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, Size(m_width,1) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( cinfo->out_color_components == 1 )
|
||||
memcpy( data, buffer[0], m_width );
|
||||
else
|
||||
icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, Size(m_width,1) );
|
||||
}
|
||||
}
|
||||
|
||||
result = true;
|
||||
jpeg_finish_decompress( cinfo );
|
||||
}
|
||||
}
|
||||
|
||||
close();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////// JpegEncoder ///////////////////
|
||||
|
||||
struct JpegDestination
|
||||
{
|
||||
struct jpeg_destination_mgr pub;
|
||||
std::vector<uchar> *buf, *dst;
|
||||
};
|
||||
|
||||
METHODDEF(void)
|
||||
stub(j_compress_ptr)
|
||||
{
|
||||
}
|
||||
|
||||
METHODDEF(void)
|
||||
term_destination (j_compress_ptr cinfo)
|
||||
{
|
||||
JpegDestination* dest = (JpegDestination*)cinfo->dest;
|
||||
size_t sz = dest->dst->size(), bufsz = dest->buf->size() - dest->pub.free_in_buffer;
|
||||
if( bufsz > 0 )
|
||||
{
|
||||
dest->dst->resize(sz + bufsz);
|
||||
memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz);
|
||||
}
|
||||
}
|
||||
|
||||
METHODDEF(boolean)
|
||||
empty_output_buffer (j_compress_ptr cinfo)
|
||||
{
|
||||
JpegDestination* dest = (JpegDestination*)cinfo->dest;
|
||||
size_t sz = dest->dst->size(), bufsz = dest->buf->size();
|
||||
dest->dst->resize(sz + bufsz);
|
||||
memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz);
|
||||
|
||||
dest->pub.next_output_byte = &(*dest->buf)[0];
|
||||
dest->pub.free_in_buffer = bufsz;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void jpeg_buffer_dest(j_compress_ptr cinfo, JpegDestination* destination)
|
||||
{
|
||||
cinfo->dest = &destination->pub;
|
||||
|
||||
destination->pub.init_destination = stub;
|
||||
destination->pub.empty_output_buffer = empty_output_buffer;
|
||||
destination->pub.term_destination = term_destination;
|
||||
}
|
||||
|
||||
|
||||
JpegEncoder::JpegEncoder()
|
||||
{
|
||||
m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)";
|
||||
m_buf_supported = true;
|
||||
}
|
||||
|
||||
|
||||
JpegEncoder::~JpegEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
ImageEncoder JpegEncoder::newEncoder() const
|
||||
{
|
||||
return makePtr<JpegEncoder>();
|
||||
}
|
||||
|
||||
bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
|
||||
{
|
||||
m_last_error.clear();
|
||||
|
||||
struct fileWrapper
|
||||
{
|
||||
FILE* f;
|
||||
|
||||
fileWrapper() : f(0) {}
|
||||
~fileWrapper() { if(f) fclose(f); }
|
||||
};
|
||||
volatile bool result = false;
|
||||
fileWrapper fw;
|
||||
int width = img.cols, height = img.rows;
|
||||
|
||||
std::vector<uchar> out_buf(1 << 12);
|
||||
AutoBuffer<uchar> _buffer;
|
||||
uchar* buffer;
|
||||
|
||||
struct jpeg_compress_struct cinfo;
|
||||
JpegErrorMgr jerr;
|
||||
JpegDestination dest;
|
||||
|
||||
jpeg_create_compress(&cinfo);
|
||||
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||
jerr.pub.error_exit = error_exit;
|
||||
|
||||
if( !m_buf )
|
||||
{
|
||||
fw.f = fopen( m_filename.c_str(), "wb" );
|
||||
if( !fw.f )
|
||||
goto _exit_;
|
||||
jpeg_stdio_dest( &cinfo, fw.f );
|
||||
}
|
||||
else
|
||||
{
|
||||
dest.dst = m_buf;
|
||||
dest.buf = &out_buf;
|
||||
|
||||
jpeg_buffer_dest( &cinfo, &dest );
|
||||
|
||||
dest.pub.next_output_byte = &out_buf[0];
|
||||
dest.pub.free_in_buffer = out_buf.size();
|
||||
}
|
||||
|
||||
if( setjmp( jerr.setjmp_buffer ) == 0 )
|
||||
{
|
||||
cinfo.image_width = width;
|
||||
cinfo.image_height = height;
|
||||
|
||||
int _channels = img.channels();
|
||||
int channels = _channels > 1 ? 3 : 1;
|
||||
cinfo.input_components = channels;
|
||||
cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE;
|
||||
|
||||
int quality = 95;
|
||||
int progressive = 0;
|
||||
int optimize = 0;
|
||||
int rst_interval = 0;
|
||||
int luma_quality = -1;
|
||||
int chroma_quality = -1;
|
||||
|
||||
for( size_t i = 0; i < params.size(); i += 2 )
|
||||
{
|
||||
if( params[i] == CV_IMWRITE_JPEG_QUALITY )
|
||||
{
|
||||
quality = params[i+1];
|
||||
quality = MIN(MAX(quality, 0), 100);
|
||||
}
|
||||
|
||||
if( params[i] == CV_IMWRITE_JPEG_PROGRESSIVE )
|
||||
{
|
||||
progressive = params[i+1];
|
||||
}
|
||||
|
||||
if( params[i] == CV_IMWRITE_JPEG_OPTIMIZE )
|
||||
{
|
||||
optimize = params[i+1];
|
||||
}
|
||||
|
||||
if( params[i] == CV_IMWRITE_JPEG_LUMA_QUALITY )
|
||||
{
|
||||
if (params[i+1] >= 0)
|
||||
{
|
||||
luma_quality = MIN(MAX(params[i+1], 0), 100);
|
||||
|
||||
quality = luma_quality;
|
||||
|
||||
if (chroma_quality < 0)
|
||||
{
|
||||
chroma_quality = luma_quality;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( params[i] == CV_IMWRITE_JPEG_CHROMA_QUALITY )
|
||||
{
|
||||
if (params[i+1] >= 0)
|
||||
{
|
||||
chroma_quality = MIN(MAX(params[i+1], 0), 100);
|
||||
}
|
||||
}
|
||||
|
||||
if( params[i] == CV_IMWRITE_JPEG_RST_INTERVAL )
|
||||
{
|
||||
rst_interval = params[i+1];
|
||||
rst_interval = MIN(MAX(rst_interval, 0), 65535L);
|
||||
}
|
||||
}
|
||||
|
||||
jpeg_set_defaults( &cinfo );
|
||||
cinfo.restart_interval = rst_interval;
|
||||
|
||||
jpeg_set_quality( &cinfo, quality,
|
||||
TRUE /* limit to baseline-JPEG values */ );
|
||||
if( progressive )
|
||||
jpeg_simple_progression( &cinfo );
|
||||
if( optimize )
|
||||
cinfo.optimize_coding = TRUE;
|
||||
|
||||
#if JPEG_LIB_VERSION >= 70
|
||||
if (luma_quality >= 0 && chroma_quality >= 0)
|
||||
{
|
||||
cinfo.q_scale_factor[0] = jpeg_quality_scaling(luma_quality);
|
||||
cinfo.q_scale_factor[1] = jpeg_quality_scaling(chroma_quality);
|
||||
if ( luma_quality != chroma_quality )
|
||||
{
|
||||
/* disable subsampling - ref. Libjpeg.txt */
|
||||
cinfo.comp_info[0].v_samp_factor = 1;
|
||||
cinfo.comp_info[0].h_samp_factor = 1;
|
||||
cinfo.comp_info[1].v_samp_factor = 1;
|
||||
cinfo.comp_info[1].h_samp_factor = 1;
|
||||
}
|
||||
jpeg_default_qtables( &cinfo, TRUE );
|
||||
}
|
||||
#endif // #if JPEG_LIB_VERSION >= 70
|
||||
|
||||
jpeg_start_compress( &cinfo, TRUE );
|
||||
|
||||
if( channels > 1 )
|
||||
_buffer.allocate(width*channels);
|
||||
buffer = _buffer.data();
|
||||
|
||||
for( int y = 0; y < height; y++ )
|
||||
{
|
||||
uchar *data = img.data + img.step*y, *ptr = data;
|
||||
|
||||
if( _channels == 3 )
|
||||
{
|
||||
icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, Size(width,1) );
|
||||
ptr = buffer;
|
||||
}
|
||||
else if( _channels == 4 )
|
||||
{
|
||||
icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, Size(width,1), 2 );
|
||||
ptr = buffer;
|
||||
}
|
||||
|
||||
jpeg_write_scanlines( &cinfo, &ptr, 1 );
|
||||
}
|
||||
|
||||
jpeg_finish_compress( &cinfo );
|
||||
result = true;
|
||||
}
|
||||
|
||||
_exit_:
|
||||
|
||||
if(!result)
|
||||
{
|
||||
char jmsg_buf[JMSG_LENGTH_MAX];
|
||||
jerr.pub.format_message((j_common_ptr)&cinfo, jmsg_buf);
|
||||
m_last_error = jmsg_buf;
|
||||
}
|
||||
|
||||
jpeg_destroy_compress( &cinfo );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* End of file. */
|
||||
113
modules/imgcodecs/src/grfmt_jpeg.hpp
Normal file
113
modules/imgcodecs/src/grfmt_jpeg.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_JPEG_H_
|
||||
#define _GRFMT_JPEG_H_
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
|
||||
// IJG-based Jpeg codec
|
||||
|
||||
namespace cv
|
||||
{
|
||||
/**
|
||||
* @brief Jpeg markers that can be encountered in a Jpeg file
|
||||
*/
|
||||
enum AppMarkerTypes
|
||||
{
|
||||
SOI = 0xD8, SOF0 = 0xC0, SOF2 = 0xC2, DHT = 0xC4,
|
||||
DQT = 0xDB, DRI = 0xDD, SOS = 0xDA,
|
||||
|
||||
RST0 = 0xD0, RST1 = 0xD1, RST2 = 0xD2, RST3 = 0xD3,
|
||||
RST4 = 0xD4, RST5 = 0xD5, RST6 = 0xD6, RST7 = 0xD7,
|
||||
|
||||
APP0 = 0xE0, APP1 = 0xE1, APP2 = 0xE2, APP3 = 0xE3,
|
||||
APP4 = 0xE4, APP5 = 0xE5, APP6 = 0xE6, APP7 = 0xE7,
|
||||
APP8 = 0xE8, APP9 = 0xE9, APP10 = 0xEA, APP11 = 0xEB,
|
||||
APP12 = 0xEC, APP13 = 0xED, APP14 = 0xEE, APP15 = 0xEF,
|
||||
|
||||
COM = 0xFE, EOI = 0xD9
|
||||
};
|
||||
|
||||
|
||||
class JpegDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
JpegDecoder();
|
||||
virtual ~JpegDecoder();
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
void close();
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
FILE* m_f;
|
||||
void* m_state;
|
||||
|
||||
private:
|
||||
JpegDecoder(const JpegDecoder &); // copy disabled
|
||||
JpegDecoder& operator=(const JpegDecoder &); // assign disabled
|
||||
};
|
||||
|
||||
|
||||
class JpegEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
JpegEncoder();
|
||||
virtual ~JpegEncoder();
|
||||
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif/*_GRFMT_JPEG_H_*/
|
||||
642
modules/imgcodecs/src/grfmt_jpeg2000.cpp
Normal file
642
modules/imgcodecs/src/grfmt_jpeg2000.cpp
Normal file
@@ -0,0 +1,642 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#ifdef HAVE_JASPER
|
||||
#include <sstream>
|
||||
|
||||
#include <opencv2/core/utils/configuration.private.hpp>
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
#include "grfmt_jpeg2000.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define JAS_WIN_MSVC_BUILD 1
|
||||
#ifdef __GNUC__
|
||||
#define HAVE_STDINT_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef VERSION
|
||||
|
||||
#include <jasper/jasper.h>
|
||||
// FIXME bad hack
|
||||
#undef uchar
|
||||
#undef ulong
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
struct JasperInitializer
|
||||
{
|
||||
JasperInitializer() { jas_init(); }
|
||||
~JasperInitializer() { jas_cleanup(); }
|
||||
};
|
||||
|
||||
static JasperInitializer& _initJasper()
|
||||
{
|
||||
static JasperInitializer initialize_jasper;
|
||||
return initialize_jasper;
|
||||
}
|
||||
|
||||
static bool isJasperEnabled()
|
||||
{
|
||||
static const bool PARAM_ENABLE_JASPER = utils::getConfigurationParameterBool("OPENCV_IO_ENABLE_JASPER",
|
||||
#ifdef OPENCV_IMGCODECS_FORCE_JASPER
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
);
|
||||
return PARAM_ENABLE_JASPER;
|
||||
}
|
||||
static JasperInitializer& initJasper()
|
||||
{
|
||||
if (isJasperEnabled())
|
||||
{
|
||||
return _initJasper();
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* message = "imgcodecs: Jasper (JPEG-2000) codec is disabled. You can enable it via 'OPENCV_IO_ENABLE_JASPER' option. Refer for details and cautions here: https://github.com/opencv/opencv/issues/14058";
|
||||
CV_LOG_WARNING(NULL, message);
|
||||
CV_Error(Error::StsNotImplemented, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////// Jpeg2KDecoder ///////////////////
|
||||
|
||||
Jpeg2KDecoder::Jpeg2KDecoder()
|
||||
{
|
||||
static const unsigned char signature_[12] = { 0, 0, 0, 0x0c, 'j', 'P', ' ', ' ', 13, 10, 0x87, 10};
|
||||
m_signature = String((const char*)signature_, (const char*)signature_ + sizeof(signature_));
|
||||
m_stream = 0;
|
||||
m_image = 0;
|
||||
}
|
||||
|
||||
|
||||
Jpeg2KDecoder::~Jpeg2KDecoder()
|
||||
{
|
||||
}
|
||||
|
||||
ImageDecoder Jpeg2KDecoder::newDecoder() const
|
||||
{
|
||||
initJasper();
|
||||
return makePtr<Jpeg2KDecoder>();
|
||||
}
|
||||
|
||||
void Jpeg2KDecoder::close()
|
||||
{
|
||||
if( m_stream )
|
||||
{
|
||||
CV_Assert(isJasperEnabled());
|
||||
jas_stream_close( (jas_stream_t*)m_stream );
|
||||
m_stream = 0;
|
||||
}
|
||||
|
||||
if( m_image )
|
||||
{
|
||||
CV_Assert(isJasperEnabled());
|
||||
jas_image_destroy( (jas_image_t*)m_image );
|
||||
m_image = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Jpeg2KDecoder::readHeader()
|
||||
{
|
||||
CV_Assert(isJasperEnabled());
|
||||
bool result = false;
|
||||
|
||||
close();
|
||||
jas_stream_t* stream = jas_stream_fopen( m_filename.c_str(), "rb" );
|
||||
m_stream = stream;
|
||||
|
||||
if( stream )
|
||||
{
|
||||
jas_image_t* image = jas_image_decode( stream, -1, 0 );
|
||||
m_image = image;
|
||||
if( image ) {
|
||||
CV_Assert(0 == (jas_image_tlx(image)) && "not supported");
|
||||
CV_Assert(0 == (jas_image_tly(image)) && "not supported");
|
||||
m_width = jas_image_width( image );
|
||||
m_height = jas_image_height( image );
|
||||
|
||||
int cntcmpts = 0; // count the known components
|
||||
int numcmpts = jas_image_numcmpts( image );
|
||||
int depth = 0;
|
||||
for( int i = 0; i < numcmpts; i++ )
|
||||
{
|
||||
int depth_i = jas_image_cmptprec( image, i );
|
||||
CV_Assert(depth == 0 || depth == depth_i); // component data type mismatch
|
||||
depth = MAX(depth, depth_i);
|
||||
if( jas_image_cmpttype( image, i ) > 2 )
|
||||
continue;
|
||||
int sgnd = jas_image_cmptsgnd(image, i);
|
||||
int xstart = jas_image_cmpttlx(image, i);
|
||||
int xend = jas_image_cmptbrx(image, i);
|
||||
int xstep = jas_image_cmpthstep(image, i);
|
||||
int ystart = jas_image_cmpttly(image, i);
|
||||
int yend = jas_image_cmptbry(image, i);
|
||||
int ystep = jas_image_cmptvstep(image, i);
|
||||
CV_Assert(sgnd == 0 && "not supported");
|
||||
CV_Assert(xstart == 0 && "not supported");
|
||||
CV_Assert(ystart == 0 && "not supported");
|
||||
CV_Assert(xstep == 1 && "not supported");
|
||||
CV_Assert(ystep == 1 && "not supported");
|
||||
CV_Assert(xend == m_width);
|
||||
CV_Assert(yend == m_height);
|
||||
cntcmpts++;
|
||||
}
|
||||
|
||||
if( cntcmpts )
|
||||
{
|
||||
CV_Assert(depth == 8 || depth == 16);
|
||||
CV_Assert(cntcmpts == 1 || cntcmpts == 3);
|
||||
m_type = CV_MAKETYPE(depth <= 8 ? CV_8U : CV_16U, cntcmpts > 1 ? 3 : 1);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !result )
|
||||
close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Jpeg2KDecoder_close(Jpeg2KDecoder* ptr)
|
||||
{
|
||||
ptr->close();
|
||||
}
|
||||
|
||||
bool Jpeg2KDecoder::readData( Mat& img )
|
||||
{
|
||||
CV_Assert(isJasperEnabled());
|
||||
|
||||
Ptr<Jpeg2KDecoder> close_this(this, Jpeg2KDecoder_close);
|
||||
bool result = false;
|
||||
bool color = img.channels() > 1;
|
||||
uchar* data = img.ptr();
|
||||
size_t step = img.step;
|
||||
jas_stream_t* stream = (jas_stream_t*)m_stream;
|
||||
jas_image_t* image = (jas_image_t*)m_image;
|
||||
|
||||
#ifndef _WIN32
|
||||
// At least on some Linux instances the
|
||||
// system libjasper segfaults when
|
||||
// converting color to grey.
|
||||
// We do this conversion manually at the end.
|
||||
Mat clr;
|
||||
if (CV_MAT_CN(img.type()) < CV_MAT_CN(this->type()))
|
||||
{
|
||||
clr.create(img.size().height, img.size().width, this->type());
|
||||
color = true;
|
||||
data = clr.ptr();
|
||||
step = (int)clr.step;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( stream && image )
|
||||
{
|
||||
bool convert;
|
||||
int colorspace;
|
||||
if( color )
|
||||
{
|
||||
convert = (jas_image_clrspc( image ) != JAS_CLRSPC_SRGB);
|
||||
colorspace = JAS_CLRSPC_SRGB;
|
||||
}
|
||||
else
|
||||
{
|
||||
convert = (jas_clrspc_fam( jas_image_clrspc( image ) ) != JAS_CLRSPC_FAM_GRAY);
|
||||
colorspace = JAS_CLRSPC_SGRAY; // TODO GENGRAY or SGRAY? (GENGRAY fails on Win.)
|
||||
}
|
||||
|
||||
// convert to the desired colorspace
|
||||
if( convert )
|
||||
{
|
||||
jas_cmprof_t *clrprof = jas_cmprof_createfromclrspc( colorspace );
|
||||
if( clrprof )
|
||||
{
|
||||
jas_image_t *_img = jas_image_chclrspc( image, clrprof, JAS_CMXFORM_INTENT_RELCLR );
|
||||
if( _img )
|
||||
{
|
||||
jas_image_destroy( image );
|
||||
m_image = image = _img;
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
jas_cmprof_destroy(clrprof);
|
||||
CV_Error(Error::StsError, "JPEG 2000 LOADER ERROR: cannot convert colorspace");
|
||||
}
|
||||
jas_cmprof_destroy( clrprof );
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Error(Error::StsError, "JPEG 2000 LOADER ERROR: unable to create colorspace");
|
||||
}
|
||||
}
|
||||
else
|
||||
result = true;
|
||||
|
||||
if( result )
|
||||
{
|
||||
int ncmpts;
|
||||
int cmptlut[3];
|
||||
if( color )
|
||||
{
|
||||
cmptlut[0] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_B );
|
||||
cmptlut[1] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_G );
|
||||
cmptlut[2] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_R );
|
||||
if( cmptlut[0] < 0 || cmptlut[1] < 0 || cmptlut[2] < 0 )
|
||||
result = false;
|
||||
ncmpts = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmptlut[0] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_GRAY_Y );
|
||||
if( cmptlut[0] < 0 )
|
||||
result = false;
|
||||
ncmpts = 1;
|
||||
}
|
||||
|
||||
if( result )
|
||||
{
|
||||
for( int i = 0; i < ncmpts; i++ )
|
||||
{
|
||||
int maxval = 1 << jas_image_cmptprec( image, cmptlut[i] );
|
||||
int offset = jas_image_cmptsgnd( image, cmptlut[i] ) ? maxval / 2 : 0;
|
||||
|
||||
int yend = jas_image_cmptbry( image, cmptlut[i] );
|
||||
int ystep = jas_image_cmptvstep( image, cmptlut[i] );
|
||||
int xend = jas_image_cmptbrx( image, cmptlut[i] );
|
||||
int xstep = jas_image_cmpthstep( image, cmptlut[i] );
|
||||
|
||||
jas_matrix_t *buffer = jas_matrix_create( yend / ystep, xend / xstep );
|
||||
if( buffer )
|
||||
{
|
||||
if( !jas_image_readcmpt( image, cmptlut[i], 0, 0, xend / xstep, yend / ystep, buffer ))
|
||||
{
|
||||
if( img.depth() == CV_8U )
|
||||
result = readComponent8u( data + i, buffer, validateToInt(step), cmptlut[i], maxval, offset, ncmpts );
|
||||
else
|
||||
result = readComponent16u( ((unsigned short *)data) + i, buffer, validateToInt(step / 2), cmptlut[i], maxval, offset, ncmpts );
|
||||
if( !result )
|
||||
{
|
||||
jas_matrix_destroy( buffer );
|
||||
CV_Error(Error::StsError, "JPEG2000 LOADER ERROR: failed to read component");
|
||||
}
|
||||
}
|
||||
jas_matrix_destroy( buffer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Error(Error::StsError, "JPEG2000 LOADER ERROR: colorspace conversion failed");
|
||||
}
|
||||
}
|
||||
|
||||
CV_Assert(result == true);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!clr.empty())
|
||||
{
|
||||
cv::cvtColor(clr, img, COLOR_BGR2GRAY);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool Jpeg2KDecoder::readComponent8u( uchar *data, void *_buffer,
|
||||
int step, int cmpt,
|
||||
int maxval, int offset, int ncmpts )
|
||||
{
|
||||
CV_Assert(isJasperEnabled());
|
||||
|
||||
jas_matrix_t* buffer = (jas_matrix_t*)_buffer;
|
||||
jas_image_t* image = (jas_image_t*)m_image;
|
||||
int xstart = jas_image_cmpttlx( image, cmpt );
|
||||
int xend = jas_image_cmptbrx( image, cmpt );
|
||||
int xstep = jas_image_cmpthstep( image, cmpt );
|
||||
int xoffset = jas_image_tlx( image );
|
||||
int ystart = jas_image_cmpttly( image, cmpt );
|
||||
int yend = jas_image_cmptbry( image, cmpt );
|
||||
int ystep = jas_image_cmptvstep( image, cmpt );
|
||||
int yoffset = jas_image_tly( image );
|
||||
int x, y, x1, y1, j;
|
||||
int rshift = cvRound(std::log(maxval/256.)/std::log(2.));
|
||||
int lshift = MAX(0, -rshift);
|
||||
rshift = MAX(0, rshift);
|
||||
int delta = (rshift > 0 ? 1 << (rshift - 1) : 0) + offset;
|
||||
|
||||
for( y = 0; y < yend - ystart; )
|
||||
{
|
||||
jas_seqent_t* pix_row = jas_matrix_getref( buffer, y / ystep, 0 );
|
||||
uchar* dst = data + (y - yoffset) * step - xoffset;
|
||||
|
||||
if( xstep == 1 )
|
||||
{
|
||||
if( maxval == 256 && offset == 0 )
|
||||
for( x = 0; x < xend - xstart; x++ )
|
||||
{
|
||||
int pix = pix_row[x];
|
||||
dst[x*ncmpts] = cv::saturate_cast<uchar>(pix);
|
||||
}
|
||||
else
|
||||
for( x = 0; x < xend - xstart; x++ )
|
||||
{
|
||||
int pix = ((pix_row[x] + delta) >> rshift) << lshift;
|
||||
dst[x*ncmpts] = cv::saturate_cast<uchar>(pix);
|
||||
}
|
||||
}
|
||||
else if( xstep == 2 && offset == 0 )
|
||||
for( x = 0, j = 0; x < xend - xstart; x += 2, j++ )
|
||||
{
|
||||
int pix = ((pix_row[j] + delta) >> rshift) << lshift;
|
||||
dst[x*ncmpts] = dst[(x+1)*ncmpts] = cv::saturate_cast<uchar>(pix);
|
||||
}
|
||||
else
|
||||
for( x = 0, j = 0; x < xend - xstart; j++ )
|
||||
{
|
||||
int pix = ((pix_row[j] + delta) >> rshift) << lshift;
|
||||
pix = cv::saturate_cast<uchar>(pix);
|
||||
for( x1 = x + xstep; x < x1; x++ )
|
||||
dst[x*ncmpts] = (uchar)pix;
|
||||
}
|
||||
y1 = y + ystep;
|
||||
for( ++y; y < y1; y++, dst += step )
|
||||
for( x = 0; x < xend - xstart; x++ )
|
||||
dst[x*ncmpts + step] = dst[x*ncmpts];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Jpeg2KDecoder::readComponent16u( unsigned short *data, void *_buffer,
|
||||
int step, int cmpt,
|
||||
int maxval, int offset, int ncmpts )
|
||||
{
|
||||
CV_Assert(isJasperEnabled());
|
||||
|
||||
jas_matrix_t* buffer = (jas_matrix_t*)_buffer;
|
||||
jas_image_t* image = (jas_image_t*)m_image;
|
||||
int xstart = jas_image_cmpttlx( image, cmpt );
|
||||
int xend = jas_image_cmptbrx( image, cmpt );
|
||||
int xstep = jas_image_cmpthstep( image, cmpt );
|
||||
int xoffset = jas_image_tlx( image );
|
||||
int ystart = jas_image_cmpttly( image, cmpt );
|
||||
int yend = jas_image_cmptbry( image, cmpt );
|
||||
int ystep = jas_image_cmptvstep( image, cmpt );
|
||||
int yoffset = jas_image_tly( image );
|
||||
int x, y, x1, y1, j;
|
||||
int rshift = cvRound(std::log(maxval/65536.)/std::log(2.));
|
||||
int lshift = MAX(0, -rshift);
|
||||
rshift = MAX(0, rshift);
|
||||
int delta = (rshift > 0 ? 1 << (rshift - 1) : 0) + offset;
|
||||
|
||||
for( y = 0; y < yend - ystart; )
|
||||
{
|
||||
jas_seqent_t* pix_row = jas_matrix_getref( buffer, y / ystep, 0 );
|
||||
ushort* dst = data + (y - yoffset) * step - xoffset;
|
||||
|
||||
if( xstep == 1 )
|
||||
{
|
||||
if( maxval == 65536 && offset == 0 )
|
||||
for( x = 0; x < xend - xstart; x++ )
|
||||
{
|
||||
int pix = pix_row[x];
|
||||
dst[x*ncmpts] = cv::saturate_cast<ushort>(pix);
|
||||
}
|
||||
else
|
||||
for( x = 0; x < xend - xstart; x++ )
|
||||
{
|
||||
int pix = ((pix_row[x] + delta) >> rshift) << lshift;
|
||||
dst[x*ncmpts] = cv::saturate_cast<ushort>(pix);
|
||||
}
|
||||
}
|
||||
else if( xstep == 2 && offset == 0 )
|
||||
for( x = 0, j = 0; x < xend - xstart; x += 2, j++ )
|
||||
{
|
||||
int pix = ((pix_row[j] + delta) >> rshift) << lshift;
|
||||
dst[x*ncmpts] = dst[(x+1)*ncmpts] = cv::saturate_cast<ushort>(pix);
|
||||
}
|
||||
else
|
||||
for( x = 0, j = 0; x < xend - xstart; j++ )
|
||||
{
|
||||
int pix = ((pix_row[j] + delta) >> rshift) << lshift;
|
||||
pix = cv::saturate_cast<ushort>(pix);
|
||||
for( x1 = x + xstep; x < x1; x++ )
|
||||
dst[x*ncmpts] = (ushort)pix;
|
||||
}
|
||||
y1 = y + ystep;
|
||||
for( ++y; y < y1; y++, dst += step )
|
||||
for( x = 0; x < xend - xstart; x++ )
|
||||
dst[x*ncmpts + step] = dst[x*ncmpts];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////// Jpeg2KEncoder ///////////////////
|
||||
|
||||
|
||||
Jpeg2KEncoder::Jpeg2KEncoder()
|
||||
{
|
||||
m_description = "JPEG-2000 files (*.jp2)";
|
||||
}
|
||||
|
||||
|
||||
Jpeg2KEncoder::~Jpeg2KEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
ImageEncoder Jpeg2KEncoder::newEncoder() const
|
||||
{
|
||||
initJasper();
|
||||
return makePtr<Jpeg2KEncoder>();
|
||||
}
|
||||
|
||||
bool Jpeg2KEncoder::isFormatSupported( int depth ) const
|
||||
{
|
||||
return depth == CV_8U || depth == CV_16U;
|
||||
}
|
||||
|
||||
|
||||
bool Jpeg2KEncoder::write( const Mat& _img, const std::vector<int>& params )
|
||||
{
|
||||
CV_Assert(isJasperEnabled());
|
||||
int width = _img.cols, height = _img.rows;
|
||||
int depth = _img.depth(), channels = _img.channels();
|
||||
depth = depth == CV_8U ? 8 : 16;
|
||||
|
||||
if( channels > 3 || channels < 1 )
|
||||
return false;
|
||||
|
||||
CV_Assert(params.size() % 2 == 0);
|
||||
double target_compression_rate = 1.0;
|
||||
for( size_t i = 0; i < params.size(); i += 2 )
|
||||
{
|
||||
switch(params[i])
|
||||
{
|
||||
case cv::IMWRITE_JPEG2000_COMPRESSION_X1000:
|
||||
target_compression_rate = std::min(std::max(params[i+1], 0), 1000) / 1000.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
jas_image_cmptparm_t component_info[3];
|
||||
for( int i = 0; i < channels; i++ )
|
||||
{
|
||||
component_info[i].tlx = 0;
|
||||
component_info[i].tly = 0;
|
||||
component_info[i].hstep = 1;
|
||||
component_info[i].vstep = 1;
|
||||
component_info[i].width = width;
|
||||
component_info[i].height = height;
|
||||
component_info[i].prec = depth;
|
||||
component_info[i].sgnd = 0;
|
||||
}
|
||||
jas_image_t *img = jas_image_create( channels, component_info, (channels == 1) ? JAS_CLRSPC_SGRAY : JAS_CLRSPC_SRGB );
|
||||
if( !img )
|
||||
return false;
|
||||
|
||||
if(channels == 1)
|
||||
jas_image_setcmpttype( img, 0, JAS_IMAGE_CT_GRAY_Y );
|
||||
else
|
||||
{
|
||||
jas_image_setcmpttype( img, 0, JAS_IMAGE_CT_RGB_B );
|
||||
jas_image_setcmpttype( img, 1, JAS_IMAGE_CT_RGB_G );
|
||||
jas_image_setcmpttype( img, 2, JAS_IMAGE_CT_RGB_R );
|
||||
}
|
||||
|
||||
bool result;
|
||||
if( depth == 8 )
|
||||
result = writeComponent8u( img, _img );
|
||||
else
|
||||
result = writeComponent16u( img, _img );
|
||||
if( result )
|
||||
{
|
||||
jas_stream_t *stream = jas_stream_fopen( m_filename.c_str(), "wb" );
|
||||
if( stream )
|
||||
{
|
||||
std::stringstream options;
|
||||
options << "rate=" << target_compression_rate;
|
||||
|
||||
result = !jas_image_encode( img, stream, jas_image_strtofmt( (char*)"jp2" ), (char*)options.str().c_str() );
|
||||
|
||||
jas_stream_close( stream );
|
||||
}
|
||||
|
||||
}
|
||||
jas_image_destroy( img );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool Jpeg2KEncoder::writeComponent8u( void *__img, const Mat& _img )
|
||||
{
|
||||
CV_Assert(isJasperEnabled());
|
||||
|
||||
jas_image_t* img = (jas_image_t*)__img;
|
||||
int w = _img.cols, h = _img.rows, ncmpts = _img.channels();
|
||||
jas_matrix_t *row = jas_matrix_create( 1, w );
|
||||
if(!row)
|
||||
return false;
|
||||
|
||||
for( int y = 0; y < h; y++ )
|
||||
{
|
||||
const uchar* data = _img.ptr(y);
|
||||
for( int i = 0; i < ncmpts; i++ )
|
||||
{
|
||||
for( int x = 0; x < w; x++)
|
||||
jas_matrix_setv( row, x, data[x * ncmpts + i] );
|
||||
jas_image_writecmpt( img, i, 0, y, w, 1, row );
|
||||
}
|
||||
}
|
||||
|
||||
jas_matrix_destroy( row );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Jpeg2KEncoder::writeComponent16u( void *__img, const Mat& _img )
|
||||
{
|
||||
CV_Assert(isJasperEnabled());
|
||||
|
||||
jas_image_t* img = (jas_image_t*)__img;
|
||||
int w = _img.cols, h = _img.rows, ncmpts = _img.channels();
|
||||
jas_matrix_t *row = jas_matrix_create( 1, w );
|
||||
if(!row)
|
||||
return false;
|
||||
|
||||
for( int y = 0; y < h; y++ )
|
||||
{
|
||||
const ushort* data = _img.ptr<ushort>(y);
|
||||
for( int i = 0; i < ncmpts; i++ )
|
||||
{
|
||||
for( int x = 0; x < w; x++)
|
||||
jas_matrix_setv( row, x, data[x * ncmpts + i] );
|
||||
jas_image_writecmpt( img, i, 0, y, w, 1, row );
|
||||
}
|
||||
}
|
||||
|
||||
jas_matrix_destroy( row );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* End of file. */
|
||||
95
modules/imgcodecs/src/grfmt_jpeg2000.hpp
Normal file
95
modules/imgcodecs/src/grfmt_jpeg2000.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_JASPER_H_
|
||||
#define _GRFMT_JASPER_H_
|
||||
|
||||
#ifdef HAVE_JASPER
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
class Jpeg2KDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
Jpeg2KDecoder();
|
||||
virtual ~Jpeg2KDecoder();
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
void close();
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
bool readComponent8u( uchar *data, void *buffer, int step, int cmpt,
|
||||
int maxval, int offset, int ncmpts );
|
||||
bool readComponent16u( unsigned short *data, void *buffer, int step, int cmpt,
|
||||
int maxval, int offset, int ncmpts );
|
||||
|
||||
void *m_stream;
|
||||
void *m_image;
|
||||
};
|
||||
|
||||
|
||||
class Jpeg2KEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
Jpeg2KEncoder();
|
||||
virtual ~Jpeg2KEncoder();
|
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
bool writeComponent8u( void *img, const Mat& _img );
|
||||
bool writeComponent16u( void *img, const Mat& _img );
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif/*_GRFMT_JASPER_H_*/
|
||||
810
modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.cpp
Normal file
810
modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.cpp
Normal file
@@ -0,0 +1,810 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2020, Stefan Brüns <stefan.bruens@rwth-aachen.de>
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#ifdef HAVE_OPENJPEG
|
||||
#include "grfmt_jpeg2000_openjpeg.hpp"
|
||||
|
||||
#include "opencv2/core/utils/logger.hpp"
|
||||
|
||||
namespace cv {
|
||||
|
||||
namespace {
|
||||
|
||||
String colorspaceName(COLOR_SPACE colorspace)
|
||||
{
|
||||
switch (colorspace)
|
||||
{
|
||||
case OPJ_CLRSPC_CMYK:
|
||||
return "CMYK";
|
||||
case OPJ_CLRSPC_SRGB:
|
||||
return "sRGB";
|
||||
case OPJ_CLRSPC_EYCC:
|
||||
return "e-YCC";
|
||||
case OPJ_CLRSPC_GRAY:
|
||||
return "grayscale";
|
||||
case OPJ_CLRSPC_SYCC:
|
||||
return "YUV";
|
||||
case OPJ_CLRSPC_UNKNOWN:
|
||||
return "unknown";
|
||||
case OPJ_CLRSPC_UNSPECIFIED:
|
||||
return "unspecified";
|
||||
default:
|
||||
CV_Error(Error::StsNotImplemented, "Invalid colorspace");
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct ConstItTraits {
|
||||
using value_type = T;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = const T*;
|
||||
using reference = const T&;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct NonConstItTraits {
|
||||
using value_type = T;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterator over the channel in continuous chunk of the memory e.g. in the one row of a Mat
|
||||
* No bounds checks are preformed due to keeping this class as simple as possible while
|
||||
* fulfilling RandomAccessIterator naming requirements.
|
||||
*
|
||||
* @tparam Traits holds information about value type and constness of the defined types
|
||||
*/
|
||||
template <class Traits>
|
||||
class ChannelsIterator
|
||||
{
|
||||
public:
|
||||
using difference_type = typename Traits::difference_type;
|
||||
using value_type = typename Traits::value_type;
|
||||
using pointer = typename Traits::pointer;
|
||||
using reference = typename Traits::reference;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
ChannelsIterator(pointer ptr, std::size_t channel, std::size_t channels_count)
|
||||
: ptr_ { ptr + channel }, step_ { channels_count }
|
||||
{
|
||||
}
|
||||
|
||||
/* Element Access */
|
||||
reference operator*() const
|
||||
{
|
||||
return *ptr_;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
return &(operator*());
|
||||
}
|
||||
|
||||
reference operator[](difference_type n) const
|
||||
{
|
||||
return *(*this + n);
|
||||
}
|
||||
|
||||
/* Iterator movement */
|
||||
ChannelsIterator<Traits>& operator++()
|
||||
{
|
||||
ptr_ += step_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ChannelsIterator<Traits> operator++(int)
|
||||
{
|
||||
ChannelsIterator ret(*this);
|
||||
++(*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ChannelsIterator<Traits>& operator--()
|
||||
{
|
||||
ptr_ -= step_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ChannelsIterator<Traits> operator--(int)
|
||||
{
|
||||
ChannelsIterator ret(*this);
|
||||
--(*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ChannelsIterator<Traits>& operator-=(difference_type n)
|
||||
{
|
||||
ptr_ -= n * step_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ChannelsIterator<Traits>& operator+=(difference_type n)
|
||||
{
|
||||
ptr_ += n * step_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ChannelsIterator<Traits> operator-(difference_type n) const
|
||||
{
|
||||
return ChannelsIterator<Traits>(*this) -= n;
|
||||
}
|
||||
|
||||
ChannelsIterator<Traits> operator+(difference_type n) const
|
||||
{
|
||||
return ChannelsIterator<Traits>(*this) += n;
|
||||
}
|
||||
|
||||
difference_type operator-(const ChannelsIterator<Traits>& other) const
|
||||
{
|
||||
return (ptr_ - other.ptr_) / step_;
|
||||
}
|
||||
|
||||
/* Comparision */
|
||||
bool operator==(const ChannelsIterator<Traits>& other) const CV_NOEXCEPT
|
||||
{
|
||||
return ptr_ == other.ptr_;
|
||||
}
|
||||
|
||||
bool operator!=(const ChannelsIterator<Traits>& other) const CV_NOEXCEPT
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool operator<(const ChannelsIterator<Traits>& other) const CV_NOEXCEPT
|
||||
{
|
||||
return ptr_ < other.ptr_;
|
||||
}
|
||||
|
||||
bool operator>(const ChannelsIterator<Traits>& other) const CV_NOEXCEPT
|
||||
{
|
||||
return other < *this;
|
||||
}
|
||||
|
||||
bool operator>=(const ChannelsIterator<Traits>& other) const CV_NOEXCEPT
|
||||
{
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
bool operator<=(const ChannelsIterator<Traits>& other) const CV_NOEXCEPT
|
||||
{
|
||||
return !(other < *this);
|
||||
}
|
||||
|
||||
private:
|
||||
pointer ptr_{nullptr};
|
||||
std::size_t step_{1};
|
||||
};
|
||||
|
||||
template <class Traits>
|
||||
inline ChannelsIterator<Traits> operator+(typename Traits::difference_type n, const ChannelsIterator<Traits>& it)
|
||||
{
|
||||
return it + n;
|
||||
}
|
||||
|
||||
template<typename OutT, typename InT>
|
||||
void copyToMatImpl(std::vector<InT*>&& in, Mat& out, uint8_t shift)
|
||||
{
|
||||
using ChannelsIt = ChannelsIterator<NonConstItTraits<OutT>>;
|
||||
|
||||
Size size = out.size();
|
||||
if (out.isContinuous())
|
||||
{
|
||||
size.width *= size.height;
|
||||
size.height = 1;
|
||||
}
|
||||
|
||||
const bool isShiftRequired = shift != 0;
|
||||
|
||||
const std::size_t channelsCount = in.size();
|
||||
|
||||
if (isShiftRequired)
|
||||
{
|
||||
for (int i = 0; i < size.height; ++i)
|
||||
{
|
||||
auto rowPtr = out.ptr<OutT>(i);
|
||||
for (std::size_t c = 0; c < channelsCount; ++c)
|
||||
{
|
||||
const auto first = in[c];
|
||||
const auto last = first + size.width;
|
||||
auto dOut = ChannelsIt(rowPtr, c, channelsCount);
|
||||
std::transform(first, last, dOut, [shift](InT val) -> OutT { return static_cast<OutT>(val >> shift); });
|
||||
in[c] += size.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < size.height; ++i)
|
||||
{
|
||||
auto rowPtr = out.ptr<OutT>(i);
|
||||
for (std::size_t c = 0; c < channelsCount; ++c)
|
||||
{
|
||||
const auto first = in[c];
|
||||
const auto last = first + size.width;
|
||||
auto dOut = ChannelsIt(rowPtr, c, channelsCount);
|
||||
std::transform(first, last, dOut, [](InT val) -> OutT { return static_cast<OutT>(val); });
|
||||
in[c] += size.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InT>
|
||||
void copyToMat(std::vector<const InT*>&& in, Mat& out, uint8_t shift)
|
||||
{
|
||||
switch (out.depth())
|
||||
{
|
||||
case CV_8U:
|
||||
copyToMatImpl<uint8_t>(std::move(in), out, shift);
|
||||
break;
|
||||
case CV_16U:
|
||||
copyToMatImpl<uint16_t>(std::move(in), out, shift);
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsNotImplemented, "only depth CV_8U and CV16_U are supported");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InT, typename OutT>
|
||||
void copyFromMatImpl(const Mat& in, std::vector<OutT*>&& out)
|
||||
{
|
||||
using ChannelsIt = ChannelsIterator<ConstItTraits<InT>>;
|
||||
|
||||
Size size = in.size();
|
||||
if (in.isContinuous())
|
||||
{
|
||||
size.width *= size.height;
|
||||
size.height = 1;
|
||||
}
|
||||
|
||||
const std::size_t outChannelsCount = out.size();
|
||||
|
||||
for (int i = 0; i < size.height; ++i)
|
||||
{
|
||||
const InT* row = in.ptr<InT>(i);
|
||||
for (std::size_t c = 0; c < outChannelsCount; ++c)
|
||||
{
|
||||
auto first = ChannelsIt(row, c, outChannelsCount);
|
||||
auto last = first + size.width;
|
||||
out[c] = std::copy(first, last, out[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename OutT>
|
||||
void copyFromMat(const Mat& in, std::vector<OutT*>&& out)
|
||||
{
|
||||
switch (in.depth())
|
||||
{
|
||||
case CV_8U:
|
||||
copyFromMatImpl<uint8_t>(in, std::move(out));
|
||||
break;
|
||||
case CV_16U:
|
||||
copyFromMatImpl<uint16_t>(in, std::move(out));
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsNotImplemented, "only depth CV_8U and CV16_U are supported");
|
||||
}
|
||||
}
|
||||
|
||||
void errorLogCallback(const char* msg, void* /* userData */)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, cv::format("OpenJPEG2000: %s", msg));
|
||||
}
|
||||
|
||||
void warningLogCallback(const char* msg, void* /* userData */)
|
||||
{
|
||||
CV_LOG_WARNING(NULL, cv::format("OpenJPEG2000: %s", msg));
|
||||
}
|
||||
|
||||
void setupLogCallbacks(opj_codec_t* codec)
|
||||
{
|
||||
if (!opj_set_error_handler(codec, errorLogCallback, nullptr))
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "OpenJPEG2000: can not set error log handler");
|
||||
}
|
||||
if (!opj_set_warning_handler(codec, warningLogCallback, nullptr))
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "OpenJPEG2000: can not set warning log handler");
|
||||
}
|
||||
}
|
||||
|
||||
opj_dparameters setupDecoderParameters()
|
||||
{
|
||||
opj_dparameters parameters;
|
||||
opj_set_default_decoder_parameters(¶meters);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
opj_cparameters setupEncoderParameters(const std::vector<int>& params)
|
||||
{
|
||||
opj_cparameters parameters;
|
||||
opj_set_default_encoder_parameters(¶meters);
|
||||
bool rate_is_specified = false;
|
||||
for (size_t i = 0; i < params.size(); i += 2)
|
||||
{
|
||||
switch (params[i])
|
||||
{
|
||||
case cv::IMWRITE_JPEG2000_COMPRESSION_X1000:
|
||||
parameters.tcp_rates[0] = 1000.f / std::min(std::max(params[i + 1], 1), 1000);
|
||||
rate_is_specified = true;
|
||||
break;
|
||||
default:
|
||||
CV_LOG_WARNING(NULL, "OpenJPEG2000(encoder): skip unsupported parameter: " << params[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
parameters.tcp_numlayers = 1;
|
||||
parameters.cp_disto_alloc = 1;
|
||||
if (!rate_is_specified)
|
||||
{
|
||||
parameters.tcp_rates[0] = 4;
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
bool decodeSRGBData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift)
|
||||
{
|
||||
using ImageComponents = std::vector<const OPJ_INT32*>;
|
||||
|
||||
const int inChannels = inImg.numcomps;
|
||||
const int outChannels = outImg.channels();
|
||||
|
||||
if (outChannels == 1)
|
||||
{
|
||||
// Assume gray (+ alpha) for 1 channels -> gray
|
||||
if (inChannels <= 2)
|
||||
{
|
||||
copyToMat(ImageComponents { inImg.comps[0].data }, outImg, shift);
|
||||
}
|
||||
// Assume RGB for >= 3 channels -> gray
|
||||
else
|
||||
{
|
||||
Mat tmp(outImg.size(), CV_MAKETYPE(outImg.depth(), 3));
|
||||
copyToMat(ImageComponents { inImg.comps[2].data, inImg.comps[1].data, inImg.comps[0].data },
|
||||
tmp, shift);
|
||||
cvtColor(tmp, outImg, COLOR_BGR2GRAY);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inChannels >= 3)
|
||||
{
|
||||
// Assume RGB (+ alpha) for 3 channels -> BGR
|
||||
ImageComponents incomps { inImg.comps[2].data, inImg.comps[1].data, inImg.comps[0].data };
|
||||
// Assume RGBA for 4 channels -> BGRA
|
||||
if (outChannels > 3)
|
||||
{
|
||||
incomps.push_back(inImg.comps[3].data);
|
||||
}
|
||||
copyToMat(std::move(incomps), outImg, shift);
|
||||
return true;
|
||||
}
|
||||
CV_LOG_ERROR(NULL,
|
||||
cv::format("OpenJPEG2000: unsupported conversion from %d components to %d for SRGB image decoding",
|
||||
inChannels, outChannels));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool decodeGrayscaleData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift)
|
||||
{
|
||||
using ImageComponents = std::vector<const OPJ_INT32*>;
|
||||
|
||||
const int inChannels = inImg.numcomps;
|
||||
const int outChannels = outImg.channels();
|
||||
|
||||
if (outChannels == 1 || outChannels == 3)
|
||||
{
|
||||
copyToMat(ImageComponents(outChannels, inImg.comps[0].data), outImg, shift);
|
||||
return true;
|
||||
}
|
||||
CV_LOG_ERROR(NULL,
|
||||
cv::format("OpenJPEG2000: unsupported conversion from %d components to %d for Grayscale image decoding",
|
||||
inChannels, outChannels));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool decodeSYCCData(const opj_image_t& inImg, cv::Mat& outImg, uint8_t shift)
|
||||
{
|
||||
using ImageComponents = std::vector<const OPJ_INT32*>;
|
||||
|
||||
const int inChannels = inImg.numcomps;
|
||||
const int outChannels = outImg.channels();
|
||||
|
||||
if (outChannels == 1) {
|
||||
copyToMat(ImageComponents { inImg.comps[0].data }, outImg, shift);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (outChannels == 3 && inChannels >= 3) {
|
||||
copyToMat(ImageComponents { inImg.comps[0].data, inImg.comps[1].data, inImg.comps[2].data },
|
||||
outImg, shift);
|
||||
cvtColor(outImg, outImg, COLOR_YUV2BGR);
|
||||
return true;
|
||||
}
|
||||
|
||||
CV_LOG_ERROR(NULL,
|
||||
cv::format("OpenJPEG2000: unsupported conversion from %d components to %d for YUV image decoding",
|
||||
inChannels, outChannels));
|
||||
return false;
|
||||
}
|
||||
|
||||
OPJ_SIZE_T opjReadFromBuffer(void* dist, OPJ_SIZE_T count, detail::OpjMemoryBuffer* buffer)
|
||||
{
|
||||
const OPJ_SIZE_T bytesToRead = std::min(buffer->availableBytes(), count);
|
||||
if (bytesToRead > 0)
|
||||
{
|
||||
memcpy(dist, buffer->pos, bytesToRead);
|
||||
buffer->pos += bytesToRead;
|
||||
return bytesToRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<OPJ_SIZE_T>(-1);
|
||||
}
|
||||
}
|
||||
|
||||
OPJ_SIZE_T opjSkipFromBuffer(OPJ_SIZE_T count, detail::OpjMemoryBuffer* buffer) {
|
||||
const OPJ_SIZE_T bytesToSkip = std::min(buffer->availableBytes(), count);
|
||||
if (bytesToSkip > 0)
|
||||
{
|
||||
buffer->pos += bytesToSkip;
|
||||
return bytesToSkip;
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<OPJ_SIZE_T>(-1);
|
||||
}
|
||||
}
|
||||
|
||||
OPJ_BOOL opjSeekFromBuffer(OPJ_OFF_T count, detail::OpjMemoryBuffer* buffer)
|
||||
{
|
||||
// Count should stay positive to prevent unsigned overflow
|
||||
CV_DbgAssert(count > 0);
|
||||
// To provide proper comparison between OPJ_OFF_T and OPJ_SIZE_T, both should be
|
||||
// casted to uint64_t (On 32-bit systems sizeof(size_t) might be 4)
|
||||
CV_DbgAssert(static_cast<uint64_t>(count) < static_cast<uint64_t>(std::numeric_limits<OPJ_SIZE_T>::max()));
|
||||
const OPJ_SIZE_T pos = std::min(buffer->length, static_cast<OPJ_SIZE_T>(count));
|
||||
buffer->pos = buffer->begin + pos;
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
detail::StreamPtr opjCreateBufferInputStream(detail::OpjMemoryBuffer* buf)
|
||||
{
|
||||
detail::StreamPtr stream{ opj_stream_default_create(/* isInput */ true) };
|
||||
if (stream)
|
||||
{
|
||||
opj_stream_set_user_data(stream.get(), static_cast<void*>(buf), nullptr);
|
||||
opj_stream_set_user_data_length(stream.get(), buf->length);
|
||||
|
||||
opj_stream_set_read_function(stream.get(), (opj_stream_read_fn)(opjReadFromBuffer));
|
||||
opj_stream_set_skip_function(stream.get(), (opj_stream_skip_fn)(opjSkipFromBuffer));
|
||||
opj_stream_set_seek_function(stream.get(), (opj_stream_seek_fn)(opjSeekFromBuffer));
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace <anonymous>
|
||||
|
||||
/////////////////////// Jpeg2KOpjDecoder ///////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
Jpeg2KOpjDecoderBase::Jpeg2KOpjDecoderBase(OPJ_CODEC_FORMAT format)
|
||||
: format_(format)
|
||||
{
|
||||
m_buf_supported = true;
|
||||
}
|
||||
|
||||
|
||||
bool Jpeg2KOpjDecoderBase::readHeader()
|
||||
{
|
||||
if (!m_buf.empty()) {
|
||||
opjBuf_ = detail::OpjMemoryBuffer(m_buf);
|
||||
stream_ = opjCreateBufferInputStream(&opjBuf_);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream_.reset(opj_stream_create_default_file_stream(m_filename.c_str(), OPJ_STREAM_READ));
|
||||
}
|
||||
if (!stream_)
|
||||
return false;
|
||||
|
||||
codec_.reset(opj_create_decompress(format_));
|
||||
if (!codec_)
|
||||
return false;
|
||||
|
||||
// Callbacks are cleared, when opj_destroy_codec is called,
|
||||
// They can provide some additional information for the user, about what goes wrong
|
||||
setupLogCallbacks(codec_.get());
|
||||
|
||||
opj_dparameters parameters = setupDecoderParameters();
|
||||
if (!opj_setup_decoder(codec_.get(), ¶meters))
|
||||
return false;
|
||||
|
||||
{
|
||||
opj_image_t* rawImage;
|
||||
if (!opj_read_header(stream_.get(), codec_.get(), &rawImage))
|
||||
return false;
|
||||
|
||||
image_.reset(rawImage);
|
||||
}
|
||||
|
||||
m_width = image_->x1 - image_->x0;
|
||||
m_height = image_->y1 - image_->y0;
|
||||
|
||||
/* Different components may have different precision,
|
||||
* so check all.
|
||||
*/
|
||||
bool hasAlpha = false;
|
||||
const int numcomps = image_->numcomps;
|
||||
CV_Assert(numcomps >= 1);
|
||||
for (int i = 0; i < numcomps; i++)
|
||||
{
|
||||
const opj_image_comp_t& comp = image_->comps[i];
|
||||
|
||||
if (comp.sgnd)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, cv::format("OpenJPEG2000: Component %d/%d is signed", i, numcomps));
|
||||
}
|
||||
|
||||
if (hasAlpha && comp.alpha)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, cv::format("OpenJPEG2000: Component %d/%d is duplicate alpha channel", i, numcomps));
|
||||
}
|
||||
|
||||
hasAlpha |= comp.alpha != 0;
|
||||
|
||||
if (comp.prec > 64)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: precision > 64 is not supported");
|
||||
}
|
||||
m_maxPrec = std::max(m_maxPrec, comp.prec);
|
||||
}
|
||||
|
||||
if (m_maxPrec < 8) {
|
||||
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: Precision < 8 not supported");
|
||||
} else if (m_maxPrec == 8) {
|
||||
m_type = CV_MAKETYPE(CV_8U, numcomps);
|
||||
} else if (m_maxPrec <= 16) {
|
||||
m_type = CV_MAKETYPE(CV_16U, numcomps);
|
||||
} else if (m_maxPrec <= 23) {
|
||||
m_type = CV_MAKETYPE(CV_32F, numcomps);
|
||||
} else {
|
||||
m_type = CV_MAKETYPE(CV_64F, numcomps);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Jpeg2KOpjDecoderBase::readData( Mat& img )
|
||||
{
|
||||
using DecodeFunc = bool(*)(const opj_image_t&, cv::Mat&, uint8_t shift);
|
||||
|
||||
if (!opj_decode(codec_.get(), stream_.get(), image_.get()))
|
||||
{
|
||||
CV_Error(Error::StsError, "OpenJPEG2000: Decoding is failed");
|
||||
}
|
||||
|
||||
if (img.channels() == 2)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented,
|
||||
cv::format("OpenJPEG2000: Unsupported number of output channels. IN: %d OUT: 2", image_->numcomps));
|
||||
}
|
||||
|
||||
DecodeFunc decode = nullptr;
|
||||
switch (image_->color_space)
|
||||
{
|
||||
case OPJ_CLRSPC_UNKNOWN:
|
||||
/* FALLTHRU */
|
||||
case OPJ_CLRSPC_UNSPECIFIED:
|
||||
CV_LOG_WARNING(NULL, "OpenJPEG2000: Image has unknown or unspecified color space, SRGB is assumed");
|
||||
/* FALLTHRU */
|
||||
case OPJ_CLRSPC_SRGB:
|
||||
decode = decodeSRGBData;
|
||||
break;
|
||||
case OPJ_CLRSPC_GRAY:
|
||||
decode = decodeGrayscaleData;
|
||||
break;
|
||||
case OPJ_CLRSPC_SYCC:
|
||||
decode = decodeSYCCData;
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsNotImplemented,
|
||||
cv::format("OpenJPEG2000: Unsupported color space conversion: %s -> %s",
|
||||
colorspaceName(image_->color_space).c_str(),
|
||||
(img.channels() == 1) ? "gray" : "BGR"));
|
||||
}
|
||||
|
||||
const int depth = img.depth();
|
||||
const OPJ_UINT32 outPrec = [depth]() {
|
||||
if (depth == CV_8U) return 8;
|
||||
if (depth == CV_16U) return 16;
|
||||
CV_Error(Error::StsNotImplemented,
|
||||
cv::format("OpenJPEG2000: output precision > 16 not supported: target depth %d", depth));
|
||||
}();
|
||||
const uint8_t shift = outPrec > m_maxPrec ? 0 : (uint8_t)(m_maxPrec - outPrec); // prec <= 64
|
||||
|
||||
const int inChannels = image_->numcomps;
|
||||
|
||||
CV_Assert(inChannels > 0);
|
||||
CV_Assert(image_->comps);
|
||||
for (int c = 0; c < inChannels; c++)
|
||||
{
|
||||
const opj_image_comp_t& comp = image_->comps[c];
|
||||
CV_CheckEQ((int)comp.dx, 1, "OpenJPEG2000: tiles are not supported");
|
||||
CV_CheckEQ((int)comp.dy, 1, "OpenJPEG2000: tiles are not supported");
|
||||
CV_CheckEQ((int)comp.x0, 0, "OpenJPEG2000: tiles are not supported");
|
||||
CV_CheckEQ((int)comp.y0, 0, "OpenJPEG2000: tiles are not supported");
|
||||
CV_CheckEQ((int)comp.w, img.cols, "OpenJPEG2000: tiles are not supported");
|
||||
CV_CheckEQ((int)comp.h, img.rows, "OpenJPEG2000: tiles are not supported");
|
||||
CV_Assert(comp.data && "OpenJPEG2000: missing component data (unsupported / broken input)");
|
||||
}
|
||||
|
||||
return decode(*image_, img, shift);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
Jpeg2KJP2OpjDecoder::Jpeg2KJP2OpjDecoder()
|
||||
: Jpeg2KOpjDecoderBase(OPJ_CODEC_JP2)
|
||||
{
|
||||
static const unsigned char JP2Signature[] = { 0, 0, 0, 0x0c, 'j', 'P', ' ', ' ', 13, 10, 0x87, 10 };
|
||||
m_signature = String((const char*) JP2Signature, sizeof(JP2Signature));
|
||||
}
|
||||
|
||||
ImageDecoder Jpeg2KJP2OpjDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<Jpeg2KJP2OpjDecoder>();
|
||||
}
|
||||
|
||||
Jpeg2KJ2KOpjDecoder::Jpeg2KJ2KOpjDecoder()
|
||||
: Jpeg2KOpjDecoderBase(OPJ_CODEC_J2K)
|
||||
{
|
||||
static const unsigned char J2KSignature[] = { 0xff, 0x4f, 0xff, 0x51 };
|
||||
m_signature = String((const char*) J2KSignature, sizeof(J2KSignature));
|
||||
}
|
||||
|
||||
ImageDecoder Jpeg2KJ2KOpjDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<Jpeg2KJ2KOpjDecoder>();
|
||||
}
|
||||
|
||||
/////////////////////// Jpeg2KOpjEncoder ///////////////////
|
||||
|
||||
Jpeg2KOpjEncoder::Jpeg2KOpjEncoder()
|
||||
{
|
||||
m_description = "JPEG-2000 files (*.jp2)";
|
||||
}
|
||||
|
||||
ImageEncoder Jpeg2KOpjEncoder::newEncoder() const
|
||||
{
|
||||
return makePtr<Jpeg2KOpjEncoder>();
|
||||
}
|
||||
|
||||
bool Jpeg2KOpjEncoder::isFormatSupported(int depth) const
|
||||
{
|
||||
return depth == CV_8U || depth == CV_16U;
|
||||
}
|
||||
|
||||
bool Jpeg2KOpjEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
{
|
||||
CV_Assert(params.size() % 2 == 0);
|
||||
|
||||
const int channels = img.channels();
|
||||
CV_DbgAssert(channels > 0); // passed matrix is not empty
|
||||
if (channels > 4)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: only BGR(a) and gray (+ alpha) images supported");
|
||||
}
|
||||
|
||||
const int depth = img.depth();
|
||||
|
||||
const OPJ_UINT32 outPrec = [depth]() {
|
||||
if (depth == CV_8U) return 8;
|
||||
if (depth == CV_16U) return 16;
|
||||
CV_Error(Error::StsNotImplemented,
|
||||
cv::format("OpenJPEG2000: image precision > 16 not supported. Got: %d", depth));
|
||||
}();
|
||||
|
||||
opj_cparameters parameters = setupEncoderParameters(params);
|
||||
|
||||
std::vector<opj_image_cmptparm_t> compparams(channels);
|
||||
for (int i = 0; i < channels; i++) {
|
||||
compparams[i].prec = outPrec;
|
||||
compparams[i].bpp = outPrec;
|
||||
compparams[i].sgnd = 0; // unsigned for now
|
||||
compparams[i].dx = parameters.subsampling_dx;
|
||||
compparams[i].dy = parameters.subsampling_dy;
|
||||
compparams[i].w = img.size().width;
|
||||
compparams[i].h = img.size().height;
|
||||
}
|
||||
|
||||
|
||||
auto colorspace = (channels > 2) ? OPJ_CLRSPC_SRGB : OPJ_CLRSPC_GRAY;
|
||||
detail::ImagePtr image(opj_image_create(channels, compparams.data(), colorspace));
|
||||
if (!image)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: can not create image");
|
||||
}
|
||||
|
||||
if (channels == 2 || channels == 4)
|
||||
{
|
||||
image->comps[channels - 1].alpha = 1;
|
||||
}
|
||||
// we want the full image
|
||||
image->x0 = 0;
|
||||
image->y0 = 0;
|
||||
image->x1 = compparams[0].dx * compparams[0].w;
|
||||
image->y1 = compparams[0].dy * compparams[0].h;
|
||||
|
||||
// fill the component data arrays
|
||||
std::vector<OPJ_INT32*> outcomps(channels, nullptr);
|
||||
if (channels == 1)
|
||||
{
|
||||
outcomps.assign({ image->comps[0].data });
|
||||
}
|
||||
else if (channels == 2)
|
||||
{
|
||||
outcomps.assign({ image->comps[0].data, image->comps[1].data });
|
||||
}
|
||||
// Reversed order for BGR -> RGB conversion
|
||||
else if (channels == 3)
|
||||
{
|
||||
outcomps.assign({ image->comps[2].data, image->comps[1].data, image->comps[0].data });
|
||||
}
|
||||
else if (channels == 4)
|
||||
{
|
||||
outcomps.assign({ image->comps[2].data, image->comps[1].data, image->comps[0].data,
|
||||
image->comps[3].data });
|
||||
}
|
||||
// outcomps holds pointers to the data, so the actual data will be modified but won't be freed
|
||||
// The container is not needed after data was copied
|
||||
copyFromMat(img, std::move(outcomps));
|
||||
|
||||
detail::CodecPtr codec(opj_create_compress(OPJ_CODEC_JP2));
|
||||
if (!codec) {
|
||||
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: can not create compression codec");
|
||||
}
|
||||
|
||||
setupLogCallbacks(codec.get());
|
||||
|
||||
if (!opj_setup_encoder(codec.get(), ¶meters, image.get()))
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: Can not setup encoder");
|
||||
}
|
||||
|
||||
detail::StreamPtr stream(opj_stream_create_default_file_stream(m_filename.c_str(), OPJ_STREAM_WRITE));
|
||||
if (!stream)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: Can not create stream");
|
||||
}
|
||||
|
||||
if (!opj_start_compress(codec.get(), image.get(), stream.get()))
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: Can not start compression");
|
||||
}
|
||||
|
||||
if (!opj_encode(codec.get(), stream.get()))
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: Encoding failed");
|
||||
}
|
||||
|
||||
if (!opj_end_compress(codec.get(), stream.get()))
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: Can not end compression");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif
|
||||
112
modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.hpp
Normal file
112
modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2020, Stefan Brüns <stefan.bruens@rwth-aachen.de>
|
||||
|
||||
#ifndef _GRFMT_OPENJPEG_H_
|
||||
#define _GRFMT_OPENJPEG_H_
|
||||
|
||||
#ifdef HAVE_OPENJPEG
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include <openjpeg.h>
|
||||
|
||||
namespace cv {
|
||||
namespace detail {
|
||||
struct OpjStreamDeleter
|
||||
{
|
||||
void operator()(opj_stream_t* stream) const
|
||||
{
|
||||
opj_stream_destroy(stream);
|
||||
}
|
||||
};
|
||||
|
||||
struct OpjCodecDeleter
|
||||
{
|
||||
void operator()(opj_codec_t* codec) const
|
||||
{
|
||||
opj_destroy_codec(codec);
|
||||
}
|
||||
};
|
||||
|
||||
struct OpjImageDeleter
|
||||
{
|
||||
void operator()(opj_image_t* image) const
|
||||
{
|
||||
opj_image_destroy(image);
|
||||
}
|
||||
};
|
||||
|
||||
struct OpjMemoryBuffer {
|
||||
OPJ_BYTE* pos{nullptr};
|
||||
OPJ_BYTE* begin{nullptr};
|
||||
OPJ_SIZE_T length{0};
|
||||
|
||||
OpjMemoryBuffer() = default;
|
||||
|
||||
explicit OpjMemoryBuffer(cv::Mat& mat)
|
||||
: pos{ mat.ptr() }, begin{ mat.ptr() }, length{ mat.rows * mat.cols * mat.elemSize() }
|
||||
{
|
||||
}
|
||||
|
||||
OPJ_SIZE_T availableBytes() const CV_NOEXCEPT {
|
||||
return begin + length - pos;
|
||||
}
|
||||
};
|
||||
|
||||
using StreamPtr = std::unique_ptr<opj_stream_t, detail::OpjStreamDeleter>;
|
||||
using CodecPtr = std::unique_ptr<opj_codec_t, detail::OpjCodecDeleter>;
|
||||
using ImagePtr = std::unique_ptr<opj_image_t, detail::OpjImageDeleter>;
|
||||
|
||||
class Jpeg2KOpjDecoderBase : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
Jpeg2KOpjDecoderBase(OPJ_CODEC_FORMAT format);
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
|
||||
private:
|
||||
detail::StreamPtr stream_{nullptr};
|
||||
detail::CodecPtr codec_{nullptr};
|
||||
detail::ImagePtr image_{nullptr};
|
||||
|
||||
detail::OpjMemoryBuffer opjBuf_;
|
||||
|
||||
OPJ_UINT32 m_maxPrec = 0;
|
||||
OPJ_CODEC_FORMAT format_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class Jpeg2KJP2OpjDecoder CV_FINAL : public detail::Jpeg2KOpjDecoderBase {
|
||||
public:
|
||||
Jpeg2KJP2OpjDecoder();
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
class Jpeg2KJ2KOpjDecoder CV_FINAL : public detail::Jpeg2KOpjDecoderBase {
|
||||
public:
|
||||
Jpeg2KJ2KOpjDecoder();
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
class Jpeg2KOpjEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
Jpeg2KOpjEncoder();
|
||||
~Jpeg2KOpjEncoder() CV_OVERRIDE = default;
|
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
} //namespace cv
|
||||
|
||||
#endif
|
||||
|
||||
#endif/*_GRFMT_OPENJPEG_H_*/
|
||||
727
modules/imgcodecs/src/grfmt_pam.cpp
Normal file
727
modules/imgcodecs/src/grfmt_pam.cpp
Normal file
@@ -0,0 +1,727 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
// (3-clause BSD License)
|
||||
//
|
||||
// Copyright (C) 2000-2016, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
|
||||
// Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved.
|
||||
// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
|
||||
// Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
|
||||
// Copyright (C) 2015-2016, Itseez Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the names of the copyright holders nor the names of the contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall copyright holders or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PXM
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "grfmt_pam.hpp"
|
||||
|
||||
namespace cv {
|
||||
|
||||
/* the PAM related fields */
|
||||
#define MAX_PAM_HEADER_IDENITFIER_LENGTH 8
|
||||
#define MAX_PAM_HEADER_VALUE_LENGTH 255
|
||||
|
||||
/* PAM header fields */
|
||||
typedef enum {
|
||||
PAM_HEADER_NONE,
|
||||
PAM_HEADER_COMMENT,
|
||||
PAM_HEADER_ENDHDR,
|
||||
PAM_HEADER_HEIGHT,
|
||||
PAM_HEADER_WIDTH,
|
||||
PAM_HEADER_DEPTH,
|
||||
PAM_HEADER_MAXVAL,
|
||||
PAM_HEADER_TUPLTYPE,
|
||||
} PamHeaderFieldType;
|
||||
|
||||
struct pam_header_field {
|
||||
PamHeaderFieldType type;
|
||||
char identifier[MAX_PAM_HEADER_IDENITFIER_LENGTH+1];
|
||||
};
|
||||
|
||||
const static struct pam_header_field fields[] = {
|
||||
{PAM_HEADER_ENDHDR, "ENDHDR"},
|
||||
{PAM_HEADER_HEIGHT, "HEIGHT"},
|
||||
{PAM_HEADER_WIDTH, "WIDTH"},
|
||||
{PAM_HEADER_DEPTH, "DEPTH"},
|
||||
{PAM_HEADER_MAXVAL, "MAXVAL"},
|
||||
{PAM_HEADER_TUPLTYPE, "TUPLTYPE"},
|
||||
};
|
||||
#define PAM_FIELDS_NO (sizeof (fields) / sizeof ((fields)[0]))
|
||||
|
||||
typedef bool (*cvtFunc) (void *src, void *target, int width, int target_channels,
|
||||
int target_depth);
|
||||
|
||||
struct channel_layout {
|
||||
uint rchan, gchan, bchan, graychan;
|
||||
};
|
||||
|
||||
struct pam_format {
|
||||
uint fmt;
|
||||
char name[MAX_PAM_HEADER_VALUE_LENGTH+1];
|
||||
cvtFunc cvt_func;
|
||||
/* the channel layout that should be used when
|
||||
* imread_ creates a 3 channel or 1 channel image
|
||||
* used when no conversion function is available
|
||||
*/
|
||||
struct channel_layout layout;
|
||||
};
|
||||
|
||||
static bool rgb_convert (void *src, void *target, int width, int target_channels,
|
||||
int target_depth);
|
||||
|
||||
const static struct pam_format formats[] = {
|
||||
{CV_IMWRITE_PAM_FORMAT_NULL, "", NULL, {0, 0, 0, 0} },
|
||||
{CV_IMWRITE_PAM_FORMAT_BLACKANDWHITE, "BLACKANDWHITE", NULL, {0, 0, 0, 0} },
|
||||
{CV_IMWRITE_PAM_FORMAT_GRAYSCALE, "GRAYSCALE", NULL, {0, 0, 0, 0} },
|
||||
{CV_IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA, "GRAYSCALE_ALPHA", NULL, {0, 0, 0, 0} },
|
||||
{CV_IMWRITE_PAM_FORMAT_RGB, "RGB", rgb_convert, {0, 1, 2, 0} },
|
||||
{CV_IMWRITE_PAM_FORMAT_RGB_ALPHA, "RGB_ALPHA", NULL, {0, 1, 2, 0} },
|
||||
};
|
||||
#define PAM_FORMATS_NO (sizeof (fields) / sizeof ((fields)[0]))
|
||||
|
||||
/*
|
||||
* conversion functions
|
||||
*/
|
||||
|
||||
static bool
|
||||
rgb_convert (void *src, void *target, int width, int target_channels, int target_depth)
|
||||
{
|
||||
bool ret = false;
|
||||
if (target_channels == 3) {
|
||||
switch (target_depth) {
|
||||
case CV_8U:
|
||||
icvCvt_RGB2BGR_8u_C3R( (uchar*) src, 0, (uchar*) target, 0,
|
||||
Size(width,1) );
|
||||
ret = true;
|
||||
break;
|
||||
case CV_16U:
|
||||
icvCvt_RGB2BGR_16u_C3R( (ushort *)src, 0, (ushort *)target, 0,
|
||||
Size(width,1) );
|
||||
ret = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (target_channels == 1) {
|
||||
switch (target_depth) {
|
||||
case CV_8U:
|
||||
icvCvt_BGR2Gray_8u_C3C1R( (uchar*) src, 0, (uchar*) target, 0,
|
||||
Size(width,1), 2 );
|
||||
ret = true;
|
||||
break;
|
||||
case CV_16U:
|
||||
icvCvt_BGRA2Gray_16u_CnC1R( (ushort *)src, 0, (ushort *)target, 0,
|
||||
Size(width,1), 3, 2 );
|
||||
ret = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy functions used as a fall back for undefined formats
|
||||
* or simpler conversion options
|
||||
*/
|
||||
|
||||
static void
|
||||
basic_conversion (void *src, const struct channel_layout *layout, int src_sampe_size,
|
||||
int src_width, void *target, int target_channels, int target_depth)
|
||||
{
|
||||
switch (target_depth) {
|
||||
case CV_8U:
|
||||
{
|
||||
uchar *d = (uchar *)target, *s = (uchar *)src,
|
||||
*end = ((uchar *)src) + src_width;
|
||||
switch (target_channels) {
|
||||
case 1:
|
||||
for( ; s < end; d += 3, s += src_sampe_size )
|
||||
d[0] = d[1] = d[2] = s[layout->graychan];
|
||||
break;
|
||||
case 3:
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
d[0] = s[layout->bchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->rchan];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CV_16U:
|
||||
{
|
||||
ushort *d = (ushort *)target, *s = (ushort *)src,
|
||||
*end = ((ushort *)src) + src_width;
|
||||
switch (target_channels) {
|
||||
case 1:
|
||||
for( ; s < end; d += 3, s += src_sampe_size )
|
||||
d[0] = d[1] = d[2] = s[layout->graychan];
|
||||
break;
|
||||
case 3:
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
d[0] = s[layout->bchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->rchan];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
bool ReadPAMHeaderLine(
|
||||
cv::RLByteStream& strm,
|
||||
CV_OUT PamHeaderFieldType &fieldtype,
|
||||
CV_OUT char value[MAX_PAM_HEADER_VALUE_LENGTH+1])
|
||||
{
|
||||
int code;
|
||||
char ident[MAX_PAM_HEADER_IDENITFIER_LENGTH+1] = {};
|
||||
|
||||
do {
|
||||
code = strm.getByte();
|
||||
} while ( isspace(code) );
|
||||
|
||||
if (code == '#') {
|
||||
/* we are in a comment, eat characters until linebreak */
|
||||
do
|
||||
{
|
||||
code = strm.getByte();
|
||||
} while( code != '\n' && code != '\r' );
|
||||
fieldtype = PAM_HEADER_COMMENT;
|
||||
return true;
|
||||
} else if (code == '\n' || code == '\r' ) {
|
||||
fieldtype = PAM_HEADER_NONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
int ident_sz = 0;
|
||||
for (; ident_sz < MAX_PAM_HEADER_IDENITFIER_LENGTH; ident_sz++)
|
||||
{
|
||||
if (isspace(code))
|
||||
break;
|
||||
ident[ident_sz] = (char)code;
|
||||
code = strm.getByte();
|
||||
}
|
||||
CV_DbgAssert(ident_sz <= MAX_PAM_HEADER_IDENITFIER_LENGTH);
|
||||
ident[ident_sz] = 0;
|
||||
|
||||
/* we may have filled the buffer and still have data */
|
||||
if (!isspace(code))
|
||||
return false;
|
||||
|
||||
bool ident_found = false;
|
||||
for (uint i = 0; i < PAM_FIELDS_NO; i++)
|
||||
{
|
||||
if (0 == strncmp(fields[i].identifier, ident, std::min(ident_sz, MAX_PAM_HEADER_IDENITFIER_LENGTH) + 1))
|
||||
{
|
||||
fieldtype = fields[i].type;
|
||||
ident_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ident_found)
|
||||
return false;
|
||||
|
||||
memset(value, 0, sizeof(char) * (MAX_PAM_HEADER_VALUE_LENGTH + 1));
|
||||
/* we may have an identifier that has no value */
|
||||
if (code == '\n' || code == '\r')
|
||||
return true;
|
||||
|
||||
do {
|
||||
code = strm.getByte();
|
||||
} while (isspace(code));
|
||||
|
||||
/* read identifier value */
|
||||
int value_sz = 0;
|
||||
for (; value_sz < MAX_PAM_HEADER_VALUE_LENGTH; value_sz++)
|
||||
{
|
||||
if (code == '\n' || code == '\r')
|
||||
break;
|
||||
value[value_sz] = (char)code;
|
||||
code = strm.getByte();
|
||||
}
|
||||
CV_DbgAssert(value_sz <= MAX_PAM_HEADER_VALUE_LENGTH);
|
||||
value[value_sz] = 0;
|
||||
|
||||
int pos = value_sz;
|
||||
|
||||
/* should be terminated */
|
||||
if (code != '\n' && code != '\r')
|
||||
return false;
|
||||
|
||||
/* remove trailing white spaces */
|
||||
while (--pos >= 0 && isspace(value[pos]))
|
||||
value[pos] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ParseInt(const char *str, int len)
|
||||
{
|
||||
CV_Assert(len > 0);
|
||||
|
||||
int pos = 0;
|
||||
bool is_negative = false;
|
||||
if (str[0] == '-')
|
||||
{
|
||||
is_negative = true;
|
||||
pos++;
|
||||
CV_Assert(isdigit(str[pos]));
|
||||
}
|
||||
uint64_t number = 0;
|
||||
while (pos < len && isdigit(str[pos]))
|
||||
{
|
||||
char ch = str[pos];
|
||||
number = (number * 10) + (uint64_t)((int)ch - (int)'0');
|
||||
CV_Assert(number < INT_MAX);
|
||||
pos++;
|
||||
}
|
||||
if (pos < len)
|
||||
CV_Assert(str[pos] == 0);
|
||||
return (is_negative) ? -(int)number : (int)number;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PAMDecoder::PAMDecoder()
|
||||
{
|
||||
m_offset = -1;
|
||||
m_buf_supported = true;
|
||||
bit_mode = false;
|
||||
selected_fmt = CV_IMWRITE_PAM_FORMAT_NULL;
|
||||
m_maxval = 0;
|
||||
m_channels = 0;
|
||||
m_sampledepth = 0;
|
||||
}
|
||||
|
||||
|
||||
PAMDecoder::~PAMDecoder()
|
||||
{
|
||||
m_strm.close();
|
||||
}
|
||||
|
||||
size_t PAMDecoder::signatureLength() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool PAMDecoder::checkSignature( const String& signature ) const
|
||||
{
|
||||
return signature.size() >= 3 && signature[0] == 'P' &&
|
||||
signature[1] == '7' &&
|
||||
isspace(signature[2]);
|
||||
}
|
||||
|
||||
ImageDecoder PAMDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<PAMDecoder>();
|
||||
}
|
||||
|
||||
bool PAMDecoder::readHeader()
|
||||
{
|
||||
PamHeaderFieldType fieldtype = PAM_HEADER_NONE;
|
||||
char value[MAX_PAM_HEADER_VALUE_LENGTH+1];
|
||||
int byte;
|
||||
|
||||
if( !m_buf.empty() )
|
||||
{
|
||||
if( !m_strm.open(m_buf) )
|
||||
return false;
|
||||
}
|
||||
else if( !m_strm.open( m_filename ))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
byte = m_strm.getByte();
|
||||
if( byte != 'P' )
|
||||
throw RBS_BAD_HEADER;
|
||||
|
||||
byte = m_strm.getByte();
|
||||
if (byte != '7')
|
||||
throw RBS_BAD_HEADER;
|
||||
|
||||
byte = m_strm.getByte();
|
||||
if (byte != '\n' && byte != '\r')
|
||||
throw RBS_BAD_HEADER;
|
||||
|
||||
bool flds_endhdr = false, flds_height = false, flds_width = false, flds_depth = false, flds_maxval = false;
|
||||
|
||||
do {
|
||||
if (!ReadPAMHeaderLine(m_strm, fieldtype, value))
|
||||
throw RBS_BAD_HEADER;
|
||||
switch (fieldtype)
|
||||
{
|
||||
case PAM_HEADER_NONE:
|
||||
case PAM_HEADER_COMMENT:
|
||||
continue;
|
||||
case PAM_HEADER_ENDHDR:
|
||||
flds_endhdr = true;
|
||||
break;
|
||||
case PAM_HEADER_HEIGHT:
|
||||
if (flds_height)
|
||||
throw RBS_BAD_HEADER;
|
||||
m_height = ParseInt(value, MAX_PAM_HEADER_VALUE_LENGTH);
|
||||
flds_height = true;
|
||||
break;
|
||||
case PAM_HEADER_WIDTH:
|
||||
if (flds_width)
|
||||
throw RBS_BAD_HEADER;
|
||||
m_width = ParseInt(value, MAX_PAM_HEADER_VALUE_LENGTH);
|
||||
flds_width = true;
|
||||
break;
|
||||
case PAM_HEADER_DEPTH:
|
||||
if (flds_depth)
|
||||
throw RBS_BAD_HEADER;
|
||||
m_channels = ParseInt(value, MAX_PAM_HEADER_VALUE_LENGTH);
|
||||
flds_depth = true;
|
||||
break;
|
||||
case PAM_HEADER_MAXVAL:
|
||||
if (flds_maxval)
|
||||
throw RBS_BAD_HEADER;
|
||||
m_maxval = ParseInt(value, MAX_PAM_HEADER_VALUE_LENGTH);
|
||||
if ( m_maxval > 65535 )
|
||||
throw RBS_BAD_HEADER;
|
||||
m_sampledepth = (m_maxval > 255) ? CV_16U : CV_8U;
|
||||
if (m_maxval == 1)
|
||||
bit_mode = true;
|
||||
flds_maxval = true;
|
||||
break;
|
||||
case PAM_HEADER_TUPLTYPE:
|
||||
{
|
||||
bool format_found = false;
|
||||
for (uint i=0; i<PAM_FORMATS_NO; i++)
|
||||
{
|
||||
if (0 == strncmp(formats[i].name, value, MAX_PAM_HEADER_VALUE_LENGTH+1))
|
||||
{
|
||||
selected_fmt = formats[i].fmt;
|
||||
format_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CV_Assert(format_found);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw RBS_BAD_HEADER;
|
||||
}
|
||||
} while (fieldtype != PAM_HEADER_ENDHDR);
|
||||
|
||||
if (flds_endhdr && flds_height && flds_width && flds_depth && flds_maxval)
|
||||
{
|
||||
if (selected_fmt == CV_IMWRITE_PAM_FORMAT_NULL)
|
||||
{
|
||||
if (m_channels == 1 && m_maxval == 1)
|
||||
selected_fmt = CV_IMWRITE_PAM_FORMAT_BLACKANDWHITE;
|
||||
else if (m_channels == 1 && m_maxval < 256)
|
||||
selected_fmt = CV_IMWRITE_PAM_FORMAT_GRAYSCALE;
|
||||
else if (m_channels == 3 && m_maxval < 256)
|
||||
selected_fmt = CV_IMWRITE_PAM_FORMAT_RGB;
|
||||
}
|
||||
m_type = CV_MAKETYPE(m_sampledepth, m_channels);
|
||||
m_offset = m_strm.getPos();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// failed
|
||||
m_offset = -1;
|
||||
m_width = m_height = -1;
|
||||
m_strm.close();
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
m_offset = -1;
|
||||
m_width = m_height = -1;
|
||||
m_strm.close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PAMDecoder::readData(Mat& img)
|
||||
{
|
||||
uchar* data = img.ptr();
|
||||
const int target_channels = img.channels();
|
||||
size_t imp_stride = img.step;
|
||||
const int sample_depth = CV_ELEM_SIZE1(m_type);
|
||||
const int src_elems_per_row = m_width*m_channels;
|
||||
const int src_stride = src_elems_per_row*sample_depth;
|
||||
PaletteEntry palette[256] = {};
|
||||
const struct pam_format *fmt = NULL;
|
||||
struct channel_layout layout = { 0, 0, 0, 0 }; // normalized to 1-channel grey format
|
||||
|
||||
/* setting buffer to max data size so scaling up is possible */
|
||||
AutoBuffer<uchar> _src(src_elems_per_row * 2);
|
||||
uchar* src = _src.data();
|
||||
|
||||
if( m_offset < 0 || !m_strm.isOpened())
|
||||
return false;
|
||||
|
||||
if (selected_fmt != CV_IMWRITE_PAM_FORMAT_NULL)
|
||||
fmt = &formats[selected_fmt];
|
||||
else {
|
||||
/* default layout handling */
|
||||
if (m_channels >= 3) {
|
||||
layout.bchan = 0;
|
||||
layout.gchan = 1;
|
||||
layout.rchan = 2;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
m_strm.setPos( m_offset );
|
||||
|
||||
/* the case where data fits the opencv matrix */
|
||||
if (m_sampledepth == img.depth() && target_channels == m_channels && !bit_mode) {
|
||||
/* special case for 16bit images with wrong endianness */
|
||||
if (m_sampledepth == CV_16U && !isBigEndian())
|
||||
{
|
||||
for (int y = 0; y < m_height; y++, data += imp_stride)
|
||||
{
|
||||
m_strm.getBytes( src, src_stride );
|
||||
for (int x = 0; x < src_elems_per_row; x++)
|
||||
{
|
||||
uchar v = src[x * 2];
|
||||
data[x * 2] = src[x * 2 + 1];
|
||||
data[x * 2 + 1] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_strm.getBytes( data, src_stride * m_height );
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
/* black and white mode */
|
||||
if (bit_mode) {
|
||||
if( target_channels == 1 )
|
||||
{
|
||||
uchar gray_palette[2] = {0, 255};
|
||||
for (int y = 0; y < m_height; y++, data += imp_stride)
|
||||
{
|
||||
m_strm.getBytes( src, src_stride );
|
||||
FillGrayRow1( data, src, m_width, gray_palette );
|
||||
}
|
||||
} else if ( target_channels == 3 )
|
||||
{
|
||||
FillGrayPalette( palette, 1 , false );
|
||||
for (int y = 0; y < m_height; y++, data += imp_stride)
|
||||
{
|
||||
m_strm.getBytes( src, src_stride );
|
||||
FillColorRow1( data, src, m_width, palette );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < m_height; y++, data += imp_stride)
|
||||
{
|
||||
m_strm.getBytes( src, src_stride );
|
||||
|
||||
/* endianness correction */
|
||||
if( m_sampledepth == CV_16U && !isBigEndian() )
|
||||
{
|
||||
for (int x = 0; x < src_elems_per_row; x++)
|
||||
{
|
||||
uchar v = src[x * 2];
|
||||
src[x * 2] = src[x * 2 + 1];
|
||||
src[x * 2 + 1] = v;
|
||||
}
|
||||
}
|
||||
|
||||
/* scale down */
|
||||
if( img.depth() == CV_8U && m_sampledepth == CV_16U )
|
||||
{
|
||||
for (int x = 0; x < src_elems_per_row; x++)
|
||||
{
|
||||
int v = ((ushort *)src)[x];
|
||||
src[x] = (uchar)(v >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* if we are only scaling up/down then we can then copy the data */
|
||||
if (target_channels == m_channels) {
|
||||
memcpy (data, src, imp_stride);
|
||||
}
|
||||
/* perform correct conversion based on format */
|
||||
else if (fmt) {
|
||||
bool funcout = false;
|
||||
if (fmt->cvt_func)
|
||||
funcout = fmt->cvt_func (src, data, m_width, target_channels,
|
||||
img.depth());
|
||||
/* fall back to default if there is no conversion function or it
|
||||
* can't handle the specified characteristics
|
||||
*/
|
||||
if (!funcout)
|
||||
basic_conversion (src, &fmt->layout, m_channels,
|
||||
m_width, data, target_channels, img.depth());
|
||||
|
||||
/* default to selecting the first available channels */
|
||||
} else {
|
||||
basic_conversion (src, &layout, m_channels,
|
||||
m_width, data, target_channels, img.depth());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PAMEncoder::PAMEncoder()
|
||||
{
|
||||
m_description = "Portable arbitrary format (*.pam)";
|
||||
m_buf_supported = true;
|
||||
}
|
||||
|
||||
|
||||
PAMEncoder::~PAMEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ImageEncoder PAMEncoder::newEncoder() const
|
||||
{
|
||||
return makePtr<PAMEncoder>();
|
||||
}
|
||||
|
||||
|
||||
bool PAMEncoder::isFormatSupported( int depth ) const
|
||||
{
|
||||
return depth == CV_8U || depth == CV_16U;
|
||||
}
|
||||
|
||||
|
||||
bool PAMEncoder::write( const Mat& img, const std::vector<int>& params )
|
||||
{
|
||||
|
||||
WLByteStream strm;
|
||||
|
||||
int width = img.cols, height = img.rows;
|
||||
int stride = width*(int)img.elemSize();
|
||||
const uchar* data = img.ptr();
|
||||
const struct pam_format *fmt = NULL;
|
||||
int x, y, tmp, bufsize = 256;
|
||||
|
||||
/* parse save file type */
|
||||
for( size_t i = 0; i < params.size(); i += 2 )
|
||||
if( params[i] == CV_IMWRITE_PAM_TUPLETYPE ) {
|
||||
if ( params[i+1] > CV_IMWRITE_PAM_FORMAT_NULL &&
|
||||
params[i+1] < (int) PAM_FORMATS_NO)
|
||||
fmt = &formats[params[i+1]];
|
||||
}
|
||||
|
||||
if( m_buf )
|
||||
{
|
||||
if( !strm.open(*m_buf) )
|
||||
return false;
|
||||
m_buf->reserve( alignSize(256 + stride*height, 256));
|
||||
}
|
||||
else if( !strm.open(m_filename) )
|
||||
return false;
|
||||
|
||||
tmp = width * (int)img.elemSize();
|
||||
|
||||
if (bufsize < tmp)
|
||||
bufsize = tmp;
|
||||
|
||||
AutoBuffer<char> _buffer(bufsize);
|
||||
char* buffer = _buffer.data();
|
||||
|
||||
/* write header */
|
||||
tmp = 0;
|
||||
tmp += sprintf( buffer, "P7\n");
|
||||
tmp += sprintf( buffer + tmp, "WIDTH %d\n", width);
|
||||
tmp += sprintf( buffer + tmp, "HEIGHT %d\n", height);
|
||||
tmp += sprintf( buffer + tmp, "DEPTH %d\n", img.channels());
|
||||
tmp += sprintf( buffer + tmp, "MAXVAL %d\n", (1 << img.elemSize1()*8) - 1);
|
||||
if (fmt)
|
||||
tmp += sprintf( buffer + tmp, "TUPLTYPE %s\n", fmt->name );
|
||||
sprintf( buffer + tmp, "ENDHDR\n" );
|
||||
|
||||
strm.putBytes( buffer, (int)strlen(buffer) );
|
||||
/* write data */
|
||||
if (img.depth() == CV_8U)
|
||||
strm.putBytes( data, stride*height );
|
||||
else if (img.depth() == CV_16U) {
|
||||
/* fix endianness */
|
||||
if (!isBigEndian()) {
|
||||
for( y = 0; y < height; y++ ) {
|
||||
memcpy( buffer, img.ptr(y), stride );
|
||||
for( x = 0; x < stride; x += 2 )
|
||||
{
|
||||
uchar v = buffer[x];
|
||||
buffer[x] = buffer[x + 1];
|
||||
buffer[x + 1] = v;
|
||||
}
|
||||
strm.putBytes( buffer, stride );
|
||||
}
|
||||
} else
|
||||
strm.putBytes( data, stride*height );
|
||||
} else
|
||||
CV_Error(Error::StsInternal, "");
|
||||
|
||||
strm.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
103
modules/imgcodecs/src/grfmt_pam.hpp
Normal file
103
modules/imgcodecs/src/grfmt_pam.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
// (3-clause BSD License)
|
||||
//
|
||||
// Copyright (C) 2000-2016, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
|
||||
// Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved.
|
||||
// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
|
||||
// Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
|
||||
// Copyright (C) 2015-2016, Itseez Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the names of the copyright holders nor the names of the contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall copyright holders or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//
|
||||
//M*/
|
||||
|
||||
//Based on "imgcodecs/src/grfmt_pxm.hpp"
|
||||
//Written by Dimitrios Katsaros <patcherwork@gmail.com>
|
||||
|
||||
#ifndef _OPENCV_PAM_HPP_
|
||||
#define _OPENCV_PAM_HPP_
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PXM
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
class PAMDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
PAMDecoder();
|
||||
virtual ~PAMDecoder() CV_OVERRIDE;
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
|
||||
size_t signatureLength() const CV_OVERRIDE;
|
||||
bool checkSignature( const String& signature ) const CV_OVERRIDE;
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
RLByteStream m_strm;
|
||||
int m_maxval, m_channels, m_sampledepth, m_offset,
|
||||
selected_fmt;
|
||||
bool bit_mode;
|
||||
};
|
||||
|
||||
|
||||
class PAMEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
PAMEncoder();
|
||||
virtual ~PAMEncoder() CV_OVERRIDE;
|
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _OPENCV_PAM_HPP_ */
|
||||
264
modules/imgcodecs/src/grfmt_pfm.cpp
Normal file
264
modules/imgcodecs/src/grfmt_pfm.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "grfmt_pfm.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PFM
|
||||
|
||||
namespace {
|
||||
|
||||
static_assert(sizeof(float) == 4, "float must be 32 bit.");
|
||||
|
||||
|
||||
bool is_byte_order_swapped(double scale)
|
||||
{
|
||||
// ".pfm" format file specifies that:
|
||||
// positive scale means big endianness;
|
||||
// negative scale means little endianness.
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
return scale < 0.0;
|
||||
#else
|
||||
return scale >= 0.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void swap_endianess(uint32_t& ui)
|
||||
{
|
||||
static const uint32_t A(0x000000ffU);
|
||||
static const uint32_t B(0x0000ff00U);
|
||||
static const uint32_t C(0x00ff0000U);
|
||||
static const uint32_t D(0xff000000U);
|
||||
|
||||
ui = ( (ui & A) << 24 )
|
||||
| ( (ui & B) << 8 )
|
||||
| ( (ui & C) >> 8 )
|
||||
| ( (ui & D) >> 24 );
|
||||
}
|
||||
|
||||
template<typename T> T atoT(const std::string& s);
|
||||
template<> int atoT<int>(const std::string& s) { return std::atoi(s.c_str()); }
|
||||
template<> double atoT<double>(const std::string& s) { return std::atof(s.c_str()); }
|
||||
|
||||
template<typename T>
|
||||
T read_number(cv::RLByteStream& strm)
|
||||
{
|
||||
// should be enough to take string representation of any number
|
||||
const size_t buffer_size = 2048;
|
||||
|
||||
std::vector<char> buffer(buffer_size, 0);
|
||||
for (size_t i = 0; i < buffer_size; ++i) {
|
||||
const int intc = strm.getByte();
|
||||
CV_Assert(intc >= -128 && intc < 128);
|
||||
char c = static_cast<char>(intc);
|
||||
if (std::isspace(c)) {
|
||||
break;
|
||||
}
|
||||
buffer[i] = c;
|
||||
}
|
||||
const std::string str(buffer.begin(), buffer.end());
|
||||
return atoT<T>(str);
|
||||
}
|
||||
|
||||
template<typename T> void write_anything(cv::WLByteStream& strm, const T& t)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << t;
|
||||
strm.putBytes(ss.str().c_str(), static_cast<int>(ss.str().size()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace cv {
|
||||
|
||||
PFMDecoder::~PFMDecoder()
|
||||
{
|
||||
}
|
||||
|
||||
PFMDecoder::PFMDecoder() : m_scale_factor(0), m_swap_byte_order(false)
|
||||
{
|
||||
m_strm.close();
|
||||
}
|
||||
|
||||
bool PFMDecoder::readHeader()
|
||||
{
|
||||
if (m_buf.empty()) {
|
||||
if (!m_strm.open(m_filename)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!m_strm.open(m_buf)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_strm.getByte() != 'P') {
|
||||
CV_Error(Error::StsError, "Unexpected file type (expected P)");
|
||||
}
|
||||
|
||||
switch (m_strm.getByte()) {
|
||||
case 'f':
|
||||
m_type = CV_32FC1;
|
||||
break;
|
||||
case 'F':
|
||||
m_type = CV_32FC3;
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsError, "Unexpected file type (expected `f` or `F`)");
|
||||
}
|
||||
|
||||
if ('\n' != m_strm.getByte()) {
|
||||
CV_Error(Error::StsError, "Unexpected header format (expected line break)");
|
||||
}
|
||||
|
||||
|
||||
m_width = read_number<int>(m_strm);
|
||||
m_height = read_number<int>(m_strm);
|
||||
m_scale_factor = read_number<double>(m_strm);
|
||||
m_swap_byte_order = is_byte_order_swapped(m_scale_factor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PFMDecoder::readData(Mat& mat)
|
||||
{
|
||||
if (!m_strm.isOpened()) {
|
||||
CV_Error(Error::StsError, "Unexpected status in data stream");
|
||||
}
|
||||
|
||||
Mat buffer(mat.size(), m_type);
|
||||
for (int y = m_height - 1; y >= 0; --y) {
|
||||
m_strm.getBytes(buffer.ptr(y), static_cast<int>(m_width * buffer.elemSize()));
|
||||
if (is_byte_order_swapped(m_scale_factor)) {
|
||||
for (int i = 0; i < m_width * buffer.channels(); ++i) {
|
||||
static_assert( sizeof(uint32_t) == sizeof(float),
|
||||
"uint32_t and float must have same size." );
|
||||
swap_endianess(buffer.ptr<uint32_t>(y)[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer.channels() == 3) {
|
||||
cv::cvtColor(buffer, buffer, cv::COLOR_BGR2RGB);
|
||||
}
|
||||
|
||||
CV_Assert(fabs(m_scale_factor) > 0.0f);
|
||||
buffer *= 1.f / fabs(m_scale_factor);
|
||||
|
||||
buffer.convertTo(mat, mat.type());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t PFMDecoder::signatureLength() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool PFMDecoder::checkSignature( const String& signature ) const
|
||||
{
|
||||
return signature.size() >= 3
|
||||
&& signature[0] == 'P'
|
||||
&& ( signature[1] == 'f' || signature[1] == 'F' )
|
||||
&& isspace(signature[2]);
|
||||
}
|
||||
|
||||
void PFMDecoder::close()
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PFMEncoder::PFMEncoder()
|
||||
{
|
||||
m_description = "Portable image format - float (*.pfm)";
|
||||
}
|
||||
|
||||
PFMEncoder::~PFMEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
bool PFMEncoder::isFormatSupported(int depth) const
|
||||
{
|
||||
// any depth will be converted into 32-bit float.
|
||||
CV_UNUSED(depth);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PFMEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
{
|
||||
CV_UNUSED(params);
|
||||
|
||||
WLByteStream strm;
|
||||
if (m_buf) {
|
||||
if (!strm.open(*m_buf)) {
|
||||
return false;
|
||||
} else {
|
||||
m_buf->reserve(alignSize(256 + sizeof(float) * img.channels() * img.total(), 256));
|
||||
}
|
||||
} else if (!strm.open(m_filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Mat float_img;
|
||||
strm.putByte('P');
|
||||
switch (img.channels()) {
|
||||
case 1:
|
||||
strm.putByte('f');
|
||||
img.convertTo(float_img, CV_32FC1);
|
||||
break;
|
||||
case 3:
|
||||
strm.putByte('F');
|
||||
img.convertTo(float_img, CV_32FC3);
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "Expected 1 or 3 channel image.");
|
||||
}
|
||||
strm.putByte('\n');
|
||||
|
||||
|
||||
write_anything(strm, float_img.cols);
|
||||
strm.putByte(' ');
|
||||
write_anything(strm, float_img.rows);
|
||||
strm.putByte('\n');
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
write_anything(strm, 1.0);
|
||||
#else
|
||||
write_anything(strm, -1.0);
|
||||
#endif
|
||||
|
||||
strm.putByte('\n');
|
||||
|
||||
// Comments are not officially supported in this file format.
|
||||
// write_anything(strm, "# Generated by OpenCV " CV_VERSION "\n");
|
||||
|
||||
for (int y = float_img.rows - 1; y >= 0; --y)
|
||||
{
|
||||
if (float_img.channels() == 3) {
|
||||
const float* bgr_row = float_img.ptr<float>(y);
|
||||
size_t row_size = float_img.cols * float_img.channels();
|
||||
std::vector<float> rgb_row(row_size);
|
||||
for (int x = 0; x < float_img.cols; ++x) {
|
||||
rgb_row[x*3+0] = bgr_row[x*3+2];
|
||||
rgb_row[x*3+1] = bgr_row[x*3+1];
|
||||
rgb_row[x*3+2] = bgr_row[x*3+0];
|
||||
}
|
||||
strm.putBytes( reinterpret_cast<const uchar*>(rgb_row.data()),
|
||||
static_cast<int>(sizeof(float) * row_size) );
|
||||
} else if (float_img.channels() == 1) {
|
||||
strm.putBytes(float_img.ptr(y), sizeof(float) * float_img.cols);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // HAVE_IMGCODEC_PFM
|
||||
57
modules/imgcodecs/src/grfmt_pfm.hpp
Normal file
57
modules/imgcodecs/src/grfmt_pfm.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _GRFMT_PFM_H_
|
||||
#define _GRFMT_PFM_H_
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PFM
|
||||
namespace cv
|
||||
{
|
||||
|
||||
class PFMDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
PFMDecoder();
|
||||
virtual ~PFMDecoder() CV_OVERRIDE;
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
void close();
|
||||
|
||||
size_t signatureLength() const CV_OVERRIDE;
|
||||
bool checkSignature( const String& signature ) const CV_OVERRIDE;
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE
|
||||
{
|
||||
return makePtr<PFMDecoder>();
|
||||
}
|
||||
|
||||
private:
|
||||
RLByteStream m_strm;
|
||||
double m_scale_factor;
|
||||
bool m_swap_byte_order;
|
||||
};
|
||||
|
||||
class PFMEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
PFMEncoder();
|
||||
virtual ~PFMEncoder() CV_OVERRIDE;
|
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE
|
||||
{
|
||||
return makePtr<PFMEncoder>();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_IMGCODEC_PXM
|
||||
|
||||
#endif/*_GRFMT_PFM_H_*/
|
||||
464
modules/imgcodecs/src/grfmt_png.cpp
Normal file
464
modules/imgcodecs/src/grfmt_png.cpp
Normal file
@@ -0,0 +1,464 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
|
||||
/****************************************************************************************\
|
||||
This part of the file implements PNG codec on base of libpng library,
|
||||
in particular, this code is based on example.c from libpng
|
||||
(see otherlibs/_graphics/readme.txt for copyright notice)
|
||||
and png2bmp sample from libpng distribution (Copyright (C) 1999-2001 MIYASAKA Masaru)
|
||||
\****************************************************************************************/
|
||||
|
||||
#ifndef _LFS64_LARGEFILE
|
||||
# define _LFS64_LARGEFILE 0
|
||||
#endif
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
# define _FILE_OFFSET_BITS 0
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBPNG_PNG_H
|
||||
#include <libpng/png.h>
|
||||
#else
|
||||
#include <png.h>
|
||||
#endif
|
||||
#include <zlib.h>
|
||||
|
||||
#include "grfmt_png.hpp"
|
||||
|
||||
#if defined _MSC_VER && _MSC_VER >= 1200
|
||||
// interaction between '_setjmp' and C++ object destruction is non-portable
|
||||
#pragma warning( disable: 4611 )
|
||||
#endif
|
||||
|
||||
// the following defines are a hack to avoid multiple problems with frame pointer handling and setjmp
|
||||
// see http://gcc.gnu.org/ml/gcc/2011-10/msg00324.html for some details
|
||||
#define mingw_getsp(...) 0
|
||||
#define __builtin_frame_address(...) 0
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/////////////////////// PngDecoder ///////////////////
|
||||
|
||||
PngDecoder::PngDecoder()
|
||||
{
|
||||
m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa";
|
||||
m_color_type = 0;
|
||||
m_png_ptr = 0;
|
||||
m_info_ptr = m_end_info = 0;
|
||||
m_f = 0;
|
||||
m_buf_supported = true;
|
||||
m_buf_pos = 0;
|
||||
m_bit_depth = 0;
|
||||
}
|
||||
|
||||
|
||||
PngDecoder::~PngDecoder()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
ImageDecoder PngDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<PngDecoder>();
|
||||
}
|
||||
|
||||
void PngDecoder::close()
|
||||
{
|
||||
if( m_f )
|
||||
{
|
||||
fclose( m_f );
|
||||
m_f = 0;
|
||||
}
|
||||
|
||||
if( m_png_ptr )
|
||||
{
|
||||
png_structp png_ptr = (png_structp)m_png_ptr;
|
||||
png_infop info_ptr = (png_infop)m_info_ptr;
|
||||
png_infop end_info = (png_infop)m_end_info;
|
||||
png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
|
||||
m_png_ptr = m_info_ptr = m_end_info = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PngDecoder::readDataFromBuf( void* _png_ptr, uchar* dst, size_t size )
|
||||
{
|
||||
png_structp png_ptr = (png_structp)_png_ptr;
|
||||
PngDecoder* decoder = (PngDecoder*)(png_get_io_ptr(png_ptr));
|
||||
CV_Assert( decoder );
|
||||
const Mat& buf = decoder->m_buf;
|
||||
if( decoder->m_buf_pos + size > buf.cols*buf.rows*buf.elemSize() )
|
||||
{
|
||||
png_error(png_ptr, "PNG input buffer is incomplete");
|
||||
return;
|
||||
}
|
||||
memcpy( dst, decoder->m_buf.ptr() + decoder->m_buf_pos, size );
|
||||
decoder->m_buf_pos += size;
|
||||
}
|
||||
|
||||
bool PngDecoder::readHeader()
|
||||
{
|
||||
volatile bool result = false;
|
||||
close();
|
||||
|
||||
png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
|
||||
|
||||
if( png_ptr )
|
||||
{
|
||||
png_infop info_ptr = png_create_info_struct( png_ptr );
|
||||
png_infop end_info = png_create_info_struct( png_ptr );
|
||||
|
||||
m_png_ptr = png_ptr;
|
||||
m_info_ptr = info_ptr;
|
||||
m_end_info = end_info;
|
||||
m_buf_pos = 0;
|
||||
|
||||
if( info_ptr && end_info )
|
||||
{
|
||||
if( setjmp( png_jmpbuf( png_ptr ) ) == 0 )
|
||||
{
|
||||
if( !m_buf.empty() )
|
||||
png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf );
|
||||
else
|
||||
{
|
||||
m_f = fopen( m_filename.c_str(), "rb" );
|
||||
if( m_f )
|
||||
png_init_io( png_ptr, m_f );
|
||||
}
|
||||
|
||||
if( !m_buf.empty() || m_f )
|
||||
{
|
||||
png_uint_32 wdth, hght;
|
||||
int bit_depth, color_type, num_trans=0;
|
||||
png_bytep trans;
|
||||
png_color_16p trans_values;
|
||||
|
||||
png_read_info( png_ptr, info_ptr );
|
||||
|
||||
png_get_IHDR( png_ptr, info_ptr, &wdth, &hght,
|
||||
&bit_depth, &color_type, 0, 0, 0 );
|
||||
|
||||
m_width = (int)wdth;
|
||||
m_height = (int)hght;
|
||||
m_color_type = color_type;
|
||||
m_bit_depth = bit_depth;
|
||||
|
||||
if( bit_depth <= 8 || bit_depth == 16 )
|
||||
{
|
||||
switch(color_type)
|
||||
{
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
case PNG_COLOR_TYPE_PALETTE:
|
||||
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
|
||||
if( num_trans > 0 )
|
||||
m_type = CV_8UC4;
|
||||
else
|
||||
m_type = CV_8UC3;
|
||||
break;
|
||||
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
m_type = CV_8UC4;
|
||||
break;
|
||||
default:
|
||||
m_type = CV_8UC1;
|
||||
}
|
||||
if( bit_depth == 16 )
|
||||
m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !result )
|
||||
close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool PngDecoder::readData( Mat& img )
|
||||
{
|
||||
volatile bool result = false;
|
||||
AutoBuffer<uchar*> _buffer(m_height);
|
||||
uchar** buffer = _buffer.data();
|
||||
bool color = img.channels() > 1;
|
||||
|
||||
png_structp png_ptr = (png_structp)m_png_ptr;
|
||||
png_infop info_ptr = (png_infop)m_info_ptr;
|
||||
png_infop end_info = (png_infop)m_end_info;
|
||||
|
||||
if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
|
||||
{
|
||||
if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
|
||||
{
|
||||
int y;
|
||||
|
||||
if( img.depth() == CV_8U && m_bit_depth == 16 )
|
||||
png_set_strip_16( png_ptr );
|
||||
else if( !isBigEndian() )
|
||||
png_set_swap( png_ptr );
|
||||
|
||||
if(img.channels() < 4)
|
||||
{
|
||||
/* observation: png_read_image() writes 400 bytes beyond
|
||||
* end of data when reading a 400x118 color png
|
||||
* "mpplus_sand.png". OpenCV crashes even with demo
|
||||
* programs. Looking at the loaded image I'd say we get 4
|
||||
* bytes per pixel instead of 3 bytes per pixel. Test
|
||||
* indicate that it is a good idea to always ask for
|
||||
* stripping alpha.. 18.11.2004 Axel Walthelm
|
||||
*/
|
||||
png_set_strip_alpha( png_ptr );
|
||||
} else
|
||||
png_set_tRNS_to_alpha( png_ptr );
|
||||
|
||||
if( m_color_type == PNG_COLOR_TYPE_PALETTE )
|
||||
png_set_palette_to_rgb( png_ptr );
|
||||
|
||||
if( (m_color_type & PNG_COLOR_MASK_COLOR) == 0 && m_bit_depth < 8 )
|
||||
#if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \
|
||||
(PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18)
|
||||
png_set_expand_gray_1_2_4_to_8( png_ptr );
|
||||
#else
|
||||
png_set_gray_1_2_4_to_8( png_ptr );
|
||||
#endif
|
||||
|
||||
if( (m_color_type & PNG_COLOR_MASK_COLOR) && color )
|
||||
png_set_bgr( png_ptr ); // convert RGB to BGR
|
||||
else if( color )
|
||||
png_set_gray_to_rgb( png_ptr ); // Gray->RGB
|
||||
else
|
||||
png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray
|
||||
|
||||
png_set_interlace_handling( png_ptr );
|
||||
png_read_update_info( png_ptr, info_ptr );
|
||||
|
||||
for( y = 0; y < m_height; y++ )
|
||||
buffer[y] = img.data + y*img.step;
|
||||
|
||||
png_read_image( png_ptr, buffer );
|
||||
png_read_end( png_ptr, end_info );
|
||||
|
||||
#ifdef PNG_eXIf_SUPPORTED
|
||||
png_uint_32 num_exif = 0;
|
||||
png_bytep exif = 0;
|
||||
|
||||
// Exif info could be in info_ptr (intro_info) or end_info per specification
|
||||
if( png_get_valid(png_ptr, info_ptr, PNG_INFO_eXIf) )
|
||||
png_get_eXIf_1(png_ptr, info_ptr, &num_exif, &exif);
|
||||
else if( png_get_valid(png_ptr, end_info, PNG_INFO_eXIf) )
|
||||
png_get_eXIf_1(png_ptr, end_info, &num_exif, &exif);
|
||||
|
||||
if( exif && num_exif > 0 )
|
||||
{
|
||||
m_exif.parseExif(exif, num_exif);
|
||||
}
|
||||
#endif
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
close();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////// PngEncoder ///////////////////
|
||||
|
||||
|
||||
PngEncoder::PngEncoder()
|
||||
{
|
||||
m_description = "Portable Network Graphics files (*.png)";
|
||||
m_buf_supported = true;
|
||||
}
|
||||
|
||||
|
||||
PngEncoder::~PngEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PngEncoder::isFormatSupported( int depth ) const
|
||||
{
|
||||
return depth == CV_8U || depth == CV_16U;
|
||||
}
|
||||
|
||||
ImageEncoder PngEncoder::newEncoder() const
|
||||
{
|
||||
return makePtr<PngEncoder>();
|
||||
}
|
||||
|
||||
|
||||
void PngEncoder::writeDataToBuf(void* _png_ptr, uchar* src, size_t size)
|
||||
{
|
||||
if( size == 0 )
|
||||
return;
|
||||
png_structp png_ptr = (png_structp)_png_ptr;
|
||||
PngEncoder* encoder = (PngEncoder*)(png_get_io_ptr(png_ptr));
|
||||
CV_Assert( encoder && encoder->m_buf );
|
||||
size_t cursz = encoder->m_buf->size();
|
||||
encoder->m_buf->resize(cursz + size);
|
||||
memcpy( &(*encoder->m_buf)[cursz], src, size );
|
||||
}
|
||||
|
||||
|
||||
void PngEncoder::flushBuf(void*)
|
||||
{
|
||||
}
|
||||
|
||||
bool PngEncoder::write( const Mat& img, const std::vector<int>& params )
|
||||
{
|
||||
png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
|
||||
png_infop info_ptr = 0;
|
||||
FILE * volatile f = 0;
|
||||
int y, width = img.cols, height = img.rows;
|
||||
int depth = img.depth(), channels = img.channels();
|
||||
volatile bool result = false;
|
||||
AutoBuffer<uchar*> buffer;
|
||||
|
||||
if( depth != CV_8U && depth != CV_16U )
|
||||
return false;
|
||||
|
||||
if( png_ptr )
|
||||
{
|
||||
info_ptr = png_create_info_struct( png_ptr );
|
||||
|
||||
if( info_ptr )
|
||||
{
|
||||
if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
|
||||
{
|
||||
if( m_buf )
|
||||
{
|
||||
png_set_write_fn(png_ptr, this,
|
||||
(png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
f = fopen( m_filename.c_str(), "wb" );
|
||||
if( f )
|
||||
png_init_io( png_ptr, (png_FILE_p)f );
|
||||
}
|
||||
|
||||
int compression_level = -1; // Invalid value to allow setting 0-9 as valid
|
||||
int compression_strategy = IMWRITE_PNG_STRATEGY_RLE; // Default strategy
|
||||
bool isBilevel = false;
|
||||
|
||||
for( size_t i = 0; i < params.size(); i += 2 )
|
||||
{
|
||||
if( params[i] == IMWRITE_PNG_COMPRESSION )
|
||||
{
|
||||
compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy
|
||||
compression_level = params[i+1];
|
||||
compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION);
|
||||
}
|
||||
if( params[i] == IMWRITE_PNG_STRATEGY )
|
||||
{
|
||||
compression_strategy = params[i+1];
|
||||
compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED);
|
||||
}
|
||||
if( params[i] == IMWRITE_PNG_BILEVEL )
|
||||
{
|
||||
isBilevel = params[i+1] != 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_buf || f )
|
||||
{
|
||||
if( compression_level >= 0 )
|
||||
{
|
||||
png_set_compression_level( png_ptr, compression_level );
|
||||
}
|
||||
else
|
||||
{
|
||||
// tune parameters for speed
|
||||
// (see http://wiki.linuxquestions.org/wiki/Libpng)
|
||||
png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
|
||||
png_set_compression_level(png_ptr, Z_BEST_SPEED);
|
||||
}
|
||||
png_set_compression_strategy(png_ptr, compression_strategy);
|
||||
|
||||
png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16,
|
||||
channels == 1 ? PNG_COLOR_TYPE_GRAY :
|
||||
channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT );
|
||||
|
||||
png_write_info( png_ptr, info_ptr );
|
||||
|
||||
if (isBilevel)
|
||||
png_set_packing(png_ptr);
|
||||
|
||||
png_set_bgr( png_ptr );
|
||||
if( !isBigEndian() )
|
||||
png_set_swap( png_ptr );
|
||||
|
||||
buffer.allocate(height);
|
||||
for( y = 0; y < height; y++ )
|
||||
buffer[y] = img.data + y*img.step;
|
||||
|
||||
png_write_image( png_ptr, buffer.data() );
|
||||
png_write_end( png_ptr, info_ptr );
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
png_destroy_write_struct( &png_ptr, &info_ptr );
|
||||
if(f) fclose( (FILE*)f );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* End of file. */
|
||||
101
modules/imgcodecs/src/grfmt_png.hpp
Normal file
101
modules/imgcodecs/src/grfmt_png.hpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_PNG_H_
|
||||
#define _GRFMT_PNG_H_
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
class PngDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
PngDecoder();
|
||||
virtual ~PngDecoder();
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
void close();
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
static void readDataFromBuf(void* png_ptr, uchar* dst, size_t size);
|
||||
|
||||
int m_bit_depth;
|
||||
void* m_png_ptr; // pointer to decompression structure
|
||||
void* m_info_ptr; // pointer to image information structure
|
||||
void* m_end_info; // pointer to one more image information structure
|
||||
FILE* m_f;
|
||||
int m_color_type;
|
||||
size_t m_buf_pos;
|
||||
};
|
||||
|
||||
|
||||
class PngEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
PngEncoder();
|
||||
virtual ~PngEncoder();
|
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
static void writeDataToBuf(void* png_ptr, uchar* src, size_t size);
|
||||
static void flushBuf(void* png_ptr);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif/*_GRFMT_PNG_H_*/
|
||||
621
modules/imgcodecs/src/grfmt_pxm.cpp
Normal file
621
modules/imgcodecs/src/grfmt_pxm.cpp
Normal file
@@ -0,0 +1,621 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "grfmt_pxm.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PXM
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
///////////////////////// P?M reader //////////////////////////////
|
||||
|
||||
static int ReadNumber(RLByteStream& strm, int maxdigits = 0)
|
||||
{
|
||||
int code;
|
||||
int64 val = 0;
|
||||
int digits = 0;
|
||||
|
||||
code = strm.getByte();
|
||||
|
||||
while (!isdigit(code))
|
||||
{
|
||||
if (code == '#' )
|
||||
{
|
||||
do
|
||||
{
|
||||
code = strm.getByte();
|
||||
}
|
||||
while (code != '\n' && code != '\r');
|
||||
code = strm.getByte();
|
||||
}
|
||||
else if (isspace(code))
|
||||
{
|
||||
while (isspace(code))
|
||||
code = strm.getByte();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 1
|
||||
CV_Error_(Error::StsError, ("PXM: Unexpected code in ReadNumber(): 0x%x (%d)", code, code));
|
||||
#else
|
||||
code = strm.getByte();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
val = val*10 + (code - '0');
|
||||
CV_Assert(val <= INT_MAX && "PXM: ReadNumber(): result is too large");
|
||||
digits++;
|
||||
if (maxdigits != 0 && digits >= maxdigits) break;
|
||||
code = strm.getByte();
|
||||
}
|
||||
while (isdigit(code));
|
||||
|
||||
return (int)val;
|
||||
}
|
||||
|
||||
|
||||
PxMDecoder::PxMDecoder()
|
||||
{
|
||||
m_offset = -1;
|
||||
m_buf_supported = true;
|
||||
m_bpp = 0;
|
||||
m_binary = false;
|
||||
m_maxval = 0;
|
||||
}
|
||||
|
||||
|
||||
PxMDecoder::~PxMDecoder()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
size_t PxMDecoder::signatureLength() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool PxMDecoder::checkSignature( const String& signature ) const
|
||||
{
|
||||
return signature.size() >= 3 && signature[0] == 'P' &&
|
||||
'1' <= signature[1] && signature[1] <= '6' &&
|
||||
isspace(signature[2]);
|
||||
}
|
||||
|
||||
ImageDecoder PxMDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<PxMDecoder>();
|
||||
}
|
||||
|
||||
void PxMDecoder::close()
|
||||
{
|
||||
m_strm.close();
|
||||
}
|
||||
|
||||
|
||||
bool PxMDecoder::readHeader()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if( !m_buf.empty() )
|
||||
{
|
||||
if( !m_strm.open(m_buf) )
|
||||
return false;
|
||||
}
|
||||
else if( !m_strm.open( m_filename ))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
int code = m_strm.getByte();
|
||||
if( code != 'P' )
|
||||
throw RBS_BAD_HEADER;
|
||||
|
||||
code = m_strm.getByte();
|
||||
switch( code )
|
||||
{
|
||||
case '1': case '4': m_bpp = 1; break;
|
||||
case '2': case '5': m_bpp = 8; break;
|
||||
case '3': case '6': m_bpp = 24; break;
|
||||
default: throw RBS_BAD_HEADER;
|
||||
}
|
||||
|
||||
m_binary = code >= '4';
|
||||
m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1;
|
||||
|
||||
m_width = ReadNumber(m_strm);
|
||||
m_height = ReadNumber(m_strm);
|
||||
|
||||
m_maxval = m_bpp == 1 ? 1 : ReadNumber(m_strm);
|
||||
if( m_maxval > 65535 )
|
||||
throw RBS_BAD_HEADER;
|
||||
|
||||
//if( m_maxval > 255 ) m_binary = false; nonsense
|
||||
if( m_maxval > 255 )
|
||||
m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
|
||||
|
||||
if( m_width > 0 && m_height > 0 && m_maxval > 0 && m_maxval < (1 << 16))
|
||||
{
|
||||
m_offset = m_strm.getPos();
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
catch (const cv::Exception&)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "PXM::readHeader(): unknown C++ exception" << std::endl << std::flush;
|
||||
throw;
|
||||
}
|
||||
|
||||
if( !result )
|
||||
{
|
||||
m_offset = -1;
|
||||
m_width = m_height = -1;
|
||||
m_strm.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool PxMDecoder::readData( Mat& img )
|
||||
{
|
||||
bool color = img.channels() > 1;
|
||||
uchar* data = img.ptr();
|
||||
PaletteEntry palette[256];
|
||||
bool result = false;
|
||||
const int bit_depth = CV_ELEM_SIZE1(m_type)*8;
|
||||
const int src_pitch = divUp(m_width*m_bpp*(bit_depth/8), 8);
|
||||
int nch = CV_MAT_CN(m_type);
|
||||
int width3 = m_width*nch;
|
||||
|
||||
if( m_offset < 0 || !m_strm.isOpened())
|
||||
return false;
|
||||
|
||||
uchar gray_palette[256] = {0};
|
||||
|
||||
// create LUT for converting colors
|
||||
if( bit_depth == 8 )
|
||||
{
|
||||
CV_Assert(m_maxval < 256 && m_maxval > 0);
|
||||
|
||||
for (int i = 0; i <= m_maxval; i++)
|
||||
gray_palette[i] = (uchar)((i*255/m_maxval)^(m_bpp == 1 ? 255 : 0));
|
||||
|
||||
FillGrayPalette( palette, m_bpp==1 ? 1 : 8 , m_bpp == 1 );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_strm.setPos( m_offset );
|
||||
|
||||
switch( m_bpp )
|
||||
{
|
||||
////////////////////////// 1 BPP /////////////////////////
|
||||
case 1:
|
||||
CV_Assert(CV_MAT_DEPTH(m_type) == CV_8U);
|
||||
if( !m_binary )
|
||||
{
|
||||
AutoBuffer<uchar> _src(m_width);
|
||||
uchar* src = _src.data();
|
||||
|
||||
for (int y = 0; y < m_height; y++, data += img.step)
|
||||
{
|
||||
for (int x = 0; x < m_width; x++)
|
||||
src[x] = ReadNumber(m_strm, 1) != 0;
|
||||
|
||||
if( color )
|
||||
FillColorRow8( data, src, m_width, palette );
|
||||
else
|
||||
FillGrayRow8( data, src, m_width, gray_palette );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoBuffer<uchar> _src(src_pitch);
|
||||
uchar* src = _src.data();
|
||||
|
||||
for (int y = 0; y < m_height; y++, data += img.step)
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
|
||||
if( color )
|
||||
FillColorRow1( data, src, m_width, palette );
|
||||
else
|
||||
FillGrayRow1( data, src, m_width, gray_palette );
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
|
||||
////////////////////////// 8 BPP /////////////////////////
|
||||
case 8:
|
||||
case 24:
|
||||
{
|
||||
AutoBuffer<uchar> _src(std::max<size_t>(width3*2, src_pitch));
|
||||
uchar* src = _src.data();
|
||||
|
||||
for (int y = 0; y < m_height; y++, data += img.step)
|
||||
{
|
||||
if( !m_binary )
|
||||
{
|
||||
for (int x = 0; x < width3; x++)
|
||||
{
|
||||
int code = ReadNumber(m_strm);
|
||||
if( (unsigned)code > (unsigned)m_maxval ) code = m_maxval;
|
||||
if( bit_depth == 8 )
|
||||
src[x] = gray_palette[code];
|
||||
else
|
||||
((ushort *)src)[x] = (ushort)code;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
if( bit_depth == 16 && !isBigEndian() )
|
||||
{
|
||||
for (int x = 0; x < width3; x++)
|
||||
{
|
||||
uchar v = src[x * 2];
|
||||
src[x * 2] = src[x * 2 + 1];
|
||||
src[x * 2 + 1] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( img.depth() == CV_8U && bit_depth == 16 )
|
||||
{
|
||||
for (int x = 0; x < width3; x++)
|
||||
{
|
||||
int v = ((ushort *)src)[x];
|
||||
src[x] = (uchar)(v >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if( m_bpp == 8 ) // image has one channel
|
||||
{
|
||||
if( color )
|
||||
{
|
||||
if( img.depth() == CV_8U ) {
|
||||
uchar *d = data, *s = src, *end = src + m_width;
|
||||
for( ; s < end; d += 3, s++)
|
||||
d[0] = d[1] = d[2] = *s;
|
||||
} else {
|
||||
ushort *d = (ushort *)data, *s = (ushort *)src, *end = ((ushort *)src) + m_width;
|
||||
for( ; s < end; s++, d += 3)
|
||||
d[0] = d[1] = d[2] = *s;
|
||||
}
|
||||
}
|
||||
else
|
||||
memcpy(data, src, img.elemSize1()*m_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( color )
|
||||
{
|
||||
if( img.depth() == CV_8U )
|
||||
icvCvt_RGB2BGR_8u_C3R( src, 0, data, 0, Size(m_width,1) );
|
||||
else
|
||||
icvCvt_RGB2BGR_16u_C3R( (ushort *)src, 0, (ushort *)data, 0, Size(m_width,1) );
|
||||
}
|
||||
else if( img.depth() == CV_8U )
|
||||
icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, Size(m_width,1), 2 );
|
||||
else
|
||||
icvCvt_BGRA2Gray_16u_CnC1R( (ushort *)src, 0, (ushort *)data, 0, Size(m_width,1), 3, 2 );
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CV_Error(Error::StsError, "m_bpp is not supported");
|
||||
}
|
||||
}
|
||||
catch (const cv::Exception&)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "PXM::readData(): unknown exception" << std::endl << std::flush;
|
||||
throw;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PxMEncoder::PxMEncoder(PxMMode mode) :
|
||||
mode_(mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case PXM_TYPE_AUTO: m_description = "Portable image format - auto (*.pnm)"; break;
|
||||
case PXM_TYPE_PBM: m_description = "Portable image format - monochrome (*.pbm)"; break;
|
||||
case PXM_TYPE_PGM: m_description = "Portable image format - gray (*.pgm)"; break;
|
||||
case PXM_TYPE_PPM: m_description = "Portable image format - color (*.ppm)"; break;
|
||||
default:
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
m_buf_supported = true;
|
||||
}
|
||||
|
||||
PxMEncoder::~PxMEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
bool PxMEncoder::isFormatSupported(int depth) const
|
||||
{
|
||||
if (mode_ == PXM_TYPE_PBM)
|
||||
return depth == CV_8U;
|
||||
return depth == CV_8U || depth == CV_16U;
|
||||
}
|
||||
|
||||
bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
{
|
||||
bool isBinary = true;
|
||||
|
||||
int width = img.cols, height = img.rows;
|
||||
int _channels = img.channels(), depth = (int)img.elemSize1()*8;
|
||||
int channels = _channels > 1 ? 3 : 1;
|
||||
int fileStep = width*(int)img.elemSize();
|
||||
int x, y;
|
||||
|
||||
for( size_t i = 0; i < params.size(); i += 2 )
|
||||
{
|
||||
if( params[i] == IMWRITE_PXM_BINARY )
|
||||
isBinary = params[i+1] != 0;
|
||||
}
|
||||
|
||||
int mode = mode_;
|
||||
if (mode == PXM_TYPE_AUTO)
|
||||
{
|
||||
mode = img.channels() == 1 ? PXM_TYPE_PGM : PXM_TYPE_PPM;
|
||||
}
|
||||
|
||||
if (mode == PXM_TYPE_PGM && img.channels() > 1)
|
||||
{
|
||||
CV_Error(Error::StsBadArg, "Portable bitmap(.pgm) expects gray image");
|
||||
}
|
||||
if (mode == PXM_TYPE_PPM && img.channels() != 3)
|
||||
{
|
||||
CV_Error(Error::StsBadArg, "Portable bitmap(.ppm) expects BGR image");
|
||||
}
|
||||
if (mode == PXM_TYPE_PBM && img.type() != CV_8UC1)
|
||||
{
|
||||
CV_Error(Error::StsBadArg, "For portable bitmap(.pbm) type must be CV_8UC1");
|
||||
}
|
||||
|
||||
WLByteStream strm;
|
||||
|
||||
if( m_buf )
|
||||
{
|
||||
if( !strm.open(*m_buf) )
|
||||
return false;
|
||||
int t = CV_MAKETYPE(img.depth(), channels);
|
||||
m_buf->reserve( alignSize(256 + (isBinary ? fileStep*height :
|
||||
((t == CV_8UC1 ? 4 : t == CV_8UC3 ? 4*3+2 :
|
||||
t == CV_16UC1 ? 6 : 6*3+2)*width+1)*height), 256));
|
||||
}
|
||||
else if( !strm.open(m_filename) )
|
||||
return false;
|
||||
|
||||
int lineLength;
|
||||
int bufferSize = 128; // buffer that should fit a header
|
||||
|
||||
if( isBinary )
|
||||
lineLength = width * (int)img.elemSize();
|
||||
else
|
||||
lineLength = (6 * channels + (channels > 1 ? 2 : 0)) * width + 32;
|
||||
|
||||
if( bufferSize < lineLength )
|
||||
bufferSize = lineLength;
|
||||
|
||||
AutoBuffer<char> _buffer(bufferSize);
|
||||
char* buffer = _buffer.data();
|
||||
|
||||
// write header;
|
||||
const int code = ((mode == PXM_TYPE_PBM) ? 1 : (mode == PXM_TYPE_PGM) ? 2 : 3)
|
||||
+ (isBinary ? 3 : 0);
|
||||
|
||||
int header_sz = sprintf(buffer, "P%c\n%d %d\n",
|
||||
(char)('0' + code), width, height);
|
||||
CV_Assert(header_sz > 0);
|
||||
if (mode != PXM_TYPE_PBM)
|
||||
{
|
||||
int sz = sprintf(&buffer[header_sz], "%d\n", (1 << depth) - 1);
|
||||
CV_Assert(sz > 0);
|
||||
header_sz += sz;
|
||||
}
|
||||
|
||||
strm.putBytes(buffer, header_sz);
|
||||
|
||||
for( y = 0; y < height; y++ )
|
||||
{
|
||||
const uchar* const data = img.ptr(y);
|
||||
if( isBinary )
|
||||
{
|
||||
if (mode == PXM_TYPE_PBM)
|
||||
{
|
||||
char* ptr = buffer;
|
||||
int bcount = 7;
|
||||
char byte = 0;
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
if (bcount == 0)
|
||||
{
|
||||
if (data[x] == 0)
|
||||
byte = (byte) | 1;
|
||||
*ptr++ = byte;
|
||||
bcount = 7;
|
||||
byte = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data[x] == 0)
|
||||
byte = (byte) | (1 << bcount);
|
||||
bcount--;
|
||||
}
|
||||
}
|
||||
if (bcount != 7)
|
||||
{
|
||||
*ptr++ = byte;
|
||||
}
|
||||
strm.putBytes(buffer, (int)(ptr - buffer));
|
||||
continue;
|
||||
}
|
||||
|
||||
if( _channels == 3 )
|
||||
{
|
||||
if( depth == 8 )
|
||||
icvCvt_BGR2RGB_8u_C3R( (const uchar*)data, 0,
|
||||
(uchar*)buffer, 0, Size(width,1) );
|
||||
else
|
||||
icvCvt_BGR2RGB_16u_C3R( (const ushort*)data, 0,
|
||||
(ushort*)buffer, 0, Size(width,1) );
|
||||
}
|
||||
|
||||
// swap endianness if necessary
|
||||
if( depth == 16 && !isBigEndian() )
|
||||
{
|
||||
if( _channels == 1 )
|
||||
memcpy( buffer, data, fileStep );
|
||||
for( x = 0; x < width*channels*2; x += 2 )
|
||||
{
|
||||
uchar v = buffer[x];
|
||||
buffer[x] = buffer[x + 1];
|
||||
buffer[x + 1] = v;
|
||||
}
|
||||
}
|
||||
|
||||
strm.putBytes( (channels > 1 || depth > 8) ? buffer : (const char*)data, fileStep);
|
||||
}
|
||||
else
|
||||
{
|
||||
char* ptr = buffer;
|
||||
if (mode == PXM_TYPE_PBM)
|
||||
{
|
||||
CV_Assert(channels == 1);
|
||||
CV_Assert(depth == 8);
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
ptr[0] = data[x] ? '0' : '1';
|
||||
ptr += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( channels > 1 )
|
||||
{
|
||||
if( depth == 8 )
|
||||
{
|
||||
for( x = 0; x < width*channels; x += channels )
|
||||
{
|
||||
sprintf( ptr, "% 4d", data[x + 2] );
|
||||
ptr += 4;
|
||||
sprintf( ptr, "% 4d", data[x + 1] );
|
||||
ptr += 4;
|
||||
sprintf( ptr, "% 4d", data[x] );
|
||||
ptr += 4;
|
||||
*ptr++ = ' ';
|
||||
*ptr++ = ' ';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( x = 0; x < width*channels; x += channels )
|
||||
{
|
||||
sprintf( ptr, "% 6d", ((const ushort *)data)[x + 2] );
|
||||
ptr += 6;
|
||||
sprintf( ptr, "% 6d", ((const ushort *)data)[x + 1] );
|
||||
ptr += 6;
|
||||
sprintf( ptr, "% 6d", ((const ushort *)data)[x] );
|
||||
ptr += 6;
|
||||
*ptr++ = ' ';
|
||||
*ptr++ = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( depth == 8 )
|
||||
{
|
||||
for( x = 0; x < width; x++ )
|
||||
{
|
||||
sprintf( ptr, "% 4d", data[x] );
|
||||
ptr += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( x = 0; x < width; x++ )
|
||||
{
|
||||
sprintf( ptr, "% 6d", ((const ushort *)data)[x] );
|
||||
ptr += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ptr++ = '\n';
|
||||
|
||||
strm.putBytes( buffer, (int)(ptr - buffer) );
|
||||
}
|
||||
}
|
||||
|
||||
strm.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_IMGCODEC_PXM
|
||||
108
modules/imgcodecs/src/grfmt_pxm.hpp
Normal file
108
modules/imgcodecs/src/grfmt_pxm.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_PxM_H_
|
||||
#define _GRFMT_PxM_H_
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PXM
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
enum PxMMode
|
||||
{
|
||||
PXM_TYPE_AUTO = 0, // "auto"
|
||||
PXM_TYPE_PBM = 1, // monochrome format (single channel)
|
||||
PXM_TYPE_PGM = 2, // gray format (single channel)
|
||||
PXM_TYPE_PPM = 3 // color format
|
||||
};
|
||||
|
||||
class PxMDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
PxMDecoder();
|
||||
virtual ~PxMDecoder() CV_OVERRIDE;
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
void close();
|
||||
|
||||
size_t signatureLength() const CV_OVERRIDE;
|
||||
bool checkSignature( const String& signature ) const CV_OVERRIDE;
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
RLByteStream m_strm;
|
||||
PaletteEntry m_palette[256];
|
||||
int m_bpp;
|
||||
int m_offset;
|
||||
bool m_binary;
|
||||
int m_maxval;
|
||||
};
|
||||
|
||||
class PxMEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
PxMEncoder(PxMMode mode);
|
||||
virtual ~PxMEncoder() CV_OVERRIDE;
|
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE
|
||||
{
|
||||
return makePtr<PxMEncoder>(mode_);
|
||||
}
|
||||
|
||||
const PxMMode mode_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_IMGCODEC_PXM
|
||||
|
||||
#endif/*_GRFMT_PxM_H_*/
|
||||
433
modules/imgcodecs/src/grfmt_sunras.cpp
Normal file
433
modules/imgcodecs/src/grfmt_sunras.cpp
Normal file
@@ -0,0 +1,433 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "grfmt_sunras.hpp"
|
||||
|
||||
#ifdef HAVE_IMGCODEC_SUNRASTER
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
static const char* fmtSignSunRas = "\x59\xA6\x6A\x95";
|
||||
|
||||
/************************ Sun Raster reader *****************************/
|
||||
|
||||
SunRasterDecoder::SunRasterDecoder()
|
||||
{
|
||||
m_offset = -1;
|
||||
m_signature = fmtSignSunRas;
|
||||
m_bpp = 0;
|
||||
m_encoding = RAS_STANDARD;
|
||||
m_maptype = RMT_NONE;
|
||||
m_maplength = 0;
|
||||
}
|
||||
|
||||
|
||||
SunRasterDecoder::~SunRasterDecoder()
|
||||
{
|
||||
}
|
||||
|
||||
ImageDecoder SunRasterDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<SunRasterDecoder>();
|
||||
}
|
||||
|
||||
void SunRasterDecoder::close()
|
||||
{
|
||||
m_strm.close();
|
||||
}
|
||||
|
||||
|
||||
bool SunRasterDecoder::readHeader()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if( !m_strm.open( m_filename )) return false;
|
||||
|
||||
try
|
||||
{
|
||||
m_strm.skip( 4 );
|
||||
m_width = m_strm.getDWord();
|
||||
m_height = m_strm.getDWord();
|
||||
m_bpp = m_strm.getDWord();
|
||||
int palSize = (m_bpp > 0 && m_bpp <= 8) ? (3*(1 << m_bpp)) : 0;
|
||||
|
||||
m_strm.skip( 4 );
|
||||
m_encoding = (SunRasType)m_strm.getDWord();
|
||||
m_maptype = (SunRasMapType)m_strm.getDWord();
|
||||
m_maplength = m_strm.getDWord();
|
||||
|
||||
if( m_width > 0 && m_height > 0 &&
|
||||
(m_bpp == 1 || m_bpp == 8 || m_bpp == 24 || m_bpp == 32) &&
|
||||
(m_encoding == RAS_OLD || m_encoding == RAS_STANDARD ||
|
||||
(m_type == RAS_BYTE_ENCODED && m_bpp == 8) || m_type == RAS_FORMAT_RGB) &&
|
||||
((m_maptype == RMT_NONE && m_maplength == 0) ||
|
||||
(m_maptype == RMT_EQUAL_RGB && m_maplength <= palSize && m_maplength > 0 && m_bpp <= 8)))
|
||||
{
|
||||
memset( m_palette, 0, sizeof(m_palette));
|
||||
|
||||
if( m_maplength != 0 )
|
||||
{
|
||||
uchar buffer[256*3];
|
||||
|
||||
if( m_strm.getBytes( buffer, m_maplength ) == m_maplength )
|
||||
{
|
||||
int i;
|
||||
palSize = m_maplength/3;
|
||||
|
||||
for( i = 0; i < palSize; i++ )
|
||||
{
|
||||
m_palette[i].b = buffer[i + 2*palSize];
|
||||
m_palette[i].g = buffer[i + palSize];
|
||||
m_palette[i].r = buffer[i];
|
||||
m_palette[i].a = 0;
|
||||
}
|
||||
|
||||
m_type = IsColorPalette( m_palette, m_bpp ) ? CV_8UC3 : CV_8UC1;
|
||||
m_offset = m_strm.getPos();
|
||||
|
||||
CV_Assert(m_offset == 32 + m_maplength);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1;
|
||||
|
||||
if( CV_MAT_CN(m_type) == 1 )
|
||||
FillGrayPalette( m_palette, m_bpp );
|
||||
|
||||
m_offset = m_strm.getPos();
|
||||
|
||||
CV_Assert(m_offset == 32 + m_maplength);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
|
||||
if( !result )
|
||||
{
|
||||
m_offset = -1;
|
||||
m_width = m_height = -1;
|
||||
m_strm.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool SunRasterDecoder::readData( Mat& img )
|
||||
{
|
||||
bool color = img.channels() > 1;
|
||||
uchar* data = img.ptr();
|
||||
size_t step = img.step;
|
||||
uchar gray_palette[256] = {0};
|
||||
bool result = false;
|
||||
int src_pitch = ((m_width*m_bpp + 7)/8 + 1) & -2;
|
||||
int nch = color ? 3 : 1;
|
||||
int width3 = m_width*nch;
|
||||
int y;
|
||||
|
||||
if( m_offset < 0 || !m_strm.isOpened())
|
||||
return false;
|
||||
|
||||
AutoBuffer<uchar> _src(src_pitch + 32);
|
||||
uchar* src = _src.data();
|
||||
|
||||
if( !color && m_maptype == RMT_EQUAL_RGB )
|
||||
CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
|
||||
|
||||
try
|
||||
{
|
||||
m_strm.setPos( m_offset );
|
||||
|
||||
switch( m_bpp )
|
||||
{
|
||||
/************************* 1 BPP ************************/
|
||||
case 1:
|
||||
if( m_type != RAS_BYTE_ENCODED )
|
||||
{
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
if( color )
|
||||
FillColorRow1( data, src, m_width, m_palette );
|
||||
else
|
||||
FillGrayRow1( data, src, m_width, gray_palette );
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uchar* line_end = src + (m_width*m_bpp + 7)/8;
|
||||
uchar* tsrc = src;
|
||||
y = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int max_count = (int)(line_end - tsrc);
|
||||
int code = 0, len = 0, len1 = 0;
|
||||
|
||||
do
|
||||
{
|
||||
code = m_strm.getByte();
|
||||
if( code == 0x80 )
|
||||
{
|
||||
len = m_strm.getByte();
|
||||
if( len != 0 ) break;
|
||||
}
|
||||
tsrc[len1] = (uchar)code;
|
||||
}
|
||||
while( ++len1 < max_count );
|
||||
|
||||
tsrc += len1;
|
||||
|
||||
if( len > 0 ) // encoded mode
|
||||
{
|
||||
++len;
|
||||
code = m_strm.getByte();
|
||||
if( len > line_end - tsrc )
|
||||
{
|
||||
CV_Error(Error::StsInternal, "");
|
||||
goto bad_decoding_1bpp;
|
||||
}
|
||||
|
||||
memset( tsrc, code, len );
|
||||
tsrc += len;
|
||||
}
|
||||
|
||||
if( tsrc >= line_end )
|
||||
{
|
||||
tsrc = src;
|
||||
if( color )
|
||||
FillColorRow1( data, src, m_width, m_palette );
|
||||
else
|
||||
FillGrayRow1( data, src, m_width, gray_palette );
|
||||
data += step;
|
||||
if( ++y >= m_height ) break;
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
bad_decoding_1bpp:
|
||||
;
|
||||
}
|
||||
break;
|
||||
/************************* 8 BPP ************************/
|
||||
case 8:
|
||||
if( m_type != RAS_BYTE_ENCODED )
|
||||
{
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes( src, src_pitch );
|
||||
if( color )
|
||||
FillColorRow8( data, src, m_width, m_palette );
|
||||
else
|
||||
FillGrayRow8( data, src, m_width, gray_palette );
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
else // RLE-encoded
|
||||
{
|
||||
uchar* line_end = data + width3;
|
||||
y = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int max_count = (int)(line_end - data);
|
||||
int code = 0, len = 0, len1;
|
||||
uchar* tsrc = src;
|
||||
|
||||
do
|
||||
{
|
||||
code = m_strm.getByte();
|
||||
if( code == 0x80 )
|
||||
{
|
||||
len = m_strm.getByte();
|
||||
if( len != 0 ) break;
|
||||
}
|
||||
*tsrc++ = (uchar)code;
|
||||
}
|
||||
while( (max_count -= nch) > 0 );
|
||||
|
||||
len1 = (int)(tsrc - src);
|
||||
|
||||
if( len1 > 0 )
|
||||
{
|
||||
if( color )
|
||||
FillColorRow8( data, src, len1, m_palette );
|
||||
else
|
||||
FillGrayRow8( data, src, len1, gray_palette );
|
||||
data += len1*nch;
|
||||
}
|
||||
|
||||
if( len > 0 ) // encoded mode
|
||||
{
|
||||
len = (len + 1)*nch;
|
||||
code = m_strm.getByte();
|
||||
|
||||
if( color )
|
||||
data = FillUniColor( data, line_end, validateToInt(step), width3,
|
||||
y, m_height, len,
|
||||
m_palette[code] );
|
||||
else
|
||||
data = FillUniGray( data, line_end, validateToInt(step), width3,
|
||||
y, m_height, len,
|
||||
gray_palette[code] );
|
||||
if( y >= m_height )
|
||||
break;
|
||||
}
|
||||
|
||||
if( data == line_end )
|
||||
{
|
||||
if( m_strm.getByte() != 0 )
|
||||
goto bad_decoding_end;
|
||||
line_end += step;
|
||||
data = line_end - width3;
|
||||
if( ++y >= m_height ) break;
|
||||
}
|
||||
}
|
||||
|
||||
result = true;
|
||||
bad_decoding_end:
|
||||
;
|
||||
}
|
||||
break;
|
||||
/************************* 24 BPP ************************/
|
||||
case 24:
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
m_strm.getBytes(src, src_pitch );
|
||||
|
||||
if( color )
|
||||
{
|
||||
if( m_type == RAS_FORMAT_RGB )
|
||||
icvCvt_RGB2BGR_8u_C3R(src, 0, data, 0, Size(m_width,1) );
|
||||
else
|
||||
memcpy(data, src, std::min(step, (size_t)src_pitch));
|
||||
}
|
||||
else
|
||||
{
|
||||
icvCvt_BGR2Gray_8u_C3C1R(src, 0, data, 0, Size(m_width,1),
|
||||
m_type == RAS_FORMAT_RGB ? 2 : 0 );
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
/************************* 32 BPP ************************/
|
||||
case 32:
|
||||
for( y = 0; y < m_height; y++, data += step )
|
||||
{
|
||||
/* hack: a0 b0 g0 r0 a1 b1 g1 r1 ... are written to src + 3,
|
||||
so when we look at src + 4, we see b0 g0 r0 x b1 g1 g1 x ... */
|
||||
m_strm.getBytes( src + 3, src_pitch );
|
||||
|
||||
if( color )
|
||||
icvCvt_BGRA2BGR_8u_C4C3R( src + 4, 0, data, 0, Size(m_width,1),
|
||||
m_type == RAS_FORMAT_RGB ? 2 : 0 );
|
||||
else
|
||||
icvCvt_BGRA2Gray_8u_C4C1R( src + 4, 0, data, 0, Size(m_width,1),
|
||||
m_type == RAS_FORMAT_RGB ? 2 : 0 );
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SunRasterEncoder::SunRasterEncoder()
|
||||
{
|
||||
m_description = "Sun raster files (*.sr;*.ras)";
|
||||
}
|
||||
|
||||
|
||||
ImageEncoder SunRasterEncoder::newEncoder() const
|
||||
{
|
||||
return makePtr<SunRasterEncoder>();
|
||||
}
|
||||
|
||||
SunRasterEncoder::~SunRasterEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
bool SunRasterEncoder::write( const Mat& img, const std::vector<int>& )
|
||||
{
|
||||
bool result = false;
|
||||
int y, width = img.cols, height = img.rows, channels = img.channels();
|
||||
int fileStep = (width*channels + 1) & -2;
|
||||
WMByteStream strm;
|
||||
|
||||
if( strm.open(m_filename) )
|
||||
{
|
||||
strm.putBytes( fmtSignSunRas, (int)strlen(fmtSignSunRas) );
|
||||
strm.putDWord( width );
|
||||
strm.putDWord( height );
|
||||
strm.putDWord( channels*8 );
|
||||
strm.putDWord( fileStep*height );
|
||||
strm.putDWord( RAS_STANDARD );
|
||||
strm.putDWord( RMT_NONE );
|
||||
strm.putDWord( 0 );
|
||||
|
||||
for( y = 0; y < height; y++ )
|
||||
strm.putBytes( img.ptr(y), fileStep );
|
||||
|
||||
strm.close();
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_IMGCODEC_SUNRASTER
|
||||
109
modules/imgcodecs/src/grfmt_sunras.hpp
Normal file
109
modules/imgcodecs/src/grfmt_sunras.hpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_SUNRAS_H_
|
||||
#define _GRFMT_SUNRAS_H_
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
|
||||
#ifdef HAVE_IMGCODEC_SUNRASTER
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
enum SunRasType
|
||||
{
|
||||
RAS_OLD = 0,
|
||||
RAS_STANDARD = 1,
|
||||
RAS_BYTE_ENCODED = 2, /* RLE encoded */
|
||||
RAS_FORMAT_RGB = 3 /* RGB instead of BGR */
|
||||
};
|
||||
|
||||
enum SunRasMapType
|
||||
{
|
||||
RMT_NONE = 0, /* direct color encoding */
|
||||
RMT_EQUAL_RGB = 1 /* paletted image */
|
||||
};
|
||||
|
||||
|
||||
// Sun Raster Reader
|
||||
class SunRasterDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
SunRasterDecoder();
|
||||
virtual ~SunRasterDecoder() CV_OVERRIDE;
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
void close();
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
RMByteStream m_strm;
|
||||
PaletteEntry m_palette[256];
|
||||
int m_bpp;
|
||||
int m_offset;
|
||||
SunRasType m_encoding;
|
||||
SunRasMapType m_maptype;
|
||||
int m_maplength;
|
||||
};
|
||||
|
||||
|
||||
class SunRasterEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
SunRasterEncoder();
|
||||
virtual ~SunRasterEncoder() CV_OVERRIDE;
|
||||
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_IMGCODEC_SUNRASTER
|
||||
|
||||
#endif/*_GRFMT_SUNRAS_H_*/
|
||||
1018
modules/imgcodecs/src/grfmt_tiff.cpp
Normal file
1018
modules/imgcodecs/src/grfmt_tiff.cpp
Normal file
File diff suppressed because it is too large
Load Diff
151
modules/imgcodecs/src/grfmt_tiff.hpp
Normal file
151
modules/imgcodecs/src/grfmt_tiff.hpp
Normal file
@@ -0,0 +1,151 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_TIFF_H_
|
||||
#define _GRFMT_TIFF_H_
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
|
||||
#ifdef HAVE_TIFF
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
// native simple TIFF codec
|
||||
enum TiffCompression
|
||||
{
|
||||
TIFF_UNCOMP = 1,
|
||||
TIFF_HUFFMAN = 2,
|
||||
TIFF_PACKBITS = 32773
|
||||
};
|
||||
|
||||
enum TiffByteOrder
|
||||
{
|
||||
TIFF_ORDER_II = 0x4949,
|
||||
TIFF_ORDER_MM = 0x4d4d
|
||||
};
|
||||
|
||||
|
||||
enum TiffTag
|
||||
{
|
||||
TIFF_TAG_WIDTH = 256,
|
||||
TIFF_TAG_HEIGHT = 257,
|
||||
TIFF_TAG_BITS_PER_SAMPLE = 258,
|
||||
TIFF_TAG_COMPRESSION = 259,
|
||||
TIFF_TAG_PHOTOMETRIC = 262,
|
||||
TIFF_TAG_STRIP_OFFSETS = 273,
|
||||
TIFF_TAG_STRIP_COUNTS = 279,
|
||||
TIFF_TAG_SAMPLES_PER_PIXEL = 277,
|
||||
TIFF_TAG_ROWS_PER_STRIP = 278,
|
||||
TIFF_TAG_PLANAR_CONFIG = 284,
|
||||
TIFF_TAG_COLOR_MAP = 320
|
||||
};
|
||||
|
||||
|
||||
enum TiffFieldType
|
||||
{
|
||||
TIFF_TYPE_BYTE = 1,
|
||||
TIFF_TYPE_SHORT = 3,
|
||||
TIFF_TYPE_LONG = 4
|
||||
};
|
||||
|
||||
|
||||
// libtiff based TIFF codec
|
||||
class TiffDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
TiffDecoder();
|
||||
virtual ~TiffDecoder() CV_OVERRIDE;
|
||||
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
void close();
|
||||
bool nextPage() CV_OVERRIDE;
|
||||
|
||||
size_t signatureLength() const CV_OVERRIDE;
|
||||
bool checkSignature( const String& signature ) const CV_OVERRIDE;
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
cv::Ptr<void> m_tif;
|
||||
int normalizeChannelsNumber(int channels) const;
|
||||
bool m_hdr;
|
||||
size_t m_buf_pos;
|
||||
|
||||
private:
|
||||
TiffDecoder(const TiffDecoder &); // copy disabled
|
||||
TiffDecoder& operator=(const TiffDecoder &); // assign disabled
|
||||
};
|
||||
|
||||
// ... and writer
|
||||
class TiffEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
TiffEncoder();
|
||||
virtual ~TiffEncoder() CV_OVERRIDE;
|
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE;
|
||||
|
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
|
||||
|
||||
bool writemulti(const std::vector<Mat>& img_vec, const std::vector<int>& params) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
void writeTag( WLByteStream& strm, TiffTag tag,
|
||||
TiffFieldType fieldType,
|
||||
int count, int value );
|
||||
|
||||
bool writeLibTiff( const std::vector<Mat>& img_vec, const std::vector<int>& params );
|
||||
bool write_32FC3_SGILOG(const Mat& img, void* tif);
|
||||
|
||||
private:
|
||||
TiffEncoder(const TiffEncoder &); // copy disabled
|
||||
TiffEncoder& operator=(const TiffEncoder &); // assign disabled
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_TIFF
|
||||
|
||||
#endif/*_GRFMT_TIFF_H_*/
|
||||
326
modules/imgcodecs/src/grfmt_webp.cpp
Normal file
326
modules/imgcodecs/src/grfmt_webp.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifdef HAVE_WEBP
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <webp/decode.h>
|
||||
#include <webp/encode.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "grfmt_webp.hpp"
|
||||
|
||||
#include "opencv2/imgproc.hpp"
|
||||
|
||||
#include <opencv2/core/utils/configuration.private.hpp>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
// 64Mb limit to avoid memory DDOS
|
||||
static size_t param_maxFileSize = utils::getConfigurationParameterSizeT("OPENCV_IMGCODECS_WEBP_MAX_FILE_SIZE", 64*1024*1024);
|
||||
|
||||
static const size_t WEBP_HEADER_SIZE = 32;
|
||||
|
||||
WebPDecoder::WebPDecoder()
|
||||
{
|
||||
m_buf_supported = true;
|
||||
channels = 0;
|
||||
fs_size = 0;
|
||||
}
|
||||
|
||||
WebPDecoder::~WebPDecoder() {}
|
||||
|
||||
size_t WebPDecoder::signatureLength() const
|
||||
{
|
||||
return WEBP_HEADER_SIZE;
|
||||
}
|
||||
|
||||
bool WebPDecoder::checkSignature(const String & signature) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if(signature.size() >= WEBP_HEADER_SIZE)
|
||||
{
|
||||
WebPBitstreamFeatures features;
|
||||
if(VP8_STATUS_OK == WebPGetFeatures((uint8_t *)signature.c_str(),
|
||||
WEBP_HEADER_SIZE, &features))
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ImageDecoder WebPDecoder::newDecoder() const
|
||||
{
|
||||
return makePtr<WebPDecoder>();
|
||||
}
|
||||
|
||||
bool WebPDecoder::readHeader()
|
||||
{
|
||||
uint8_t header[WEBP_HEADER_SIZE] = { 0 };
|
||||
if (m_buf.empty())
|
||||
{
|
||||
fs.open(m_filename.c_str(), std::ios::binary);
|
||||
fs.seekg(0, std::ios::end);
|
||||
fs_size = safeCastToSizeT(fs.tellg(), "File is too large");
|
||||
fs.seekg(0, std::ios::beg);
|
||||
CV_Assert(fs && "File stream error");
|
||||
CV_CheckGE(fs_size, WEBP_HEADER_SIZE, "File is too small");
|
||||
CV_CheckLE(fs_size, param_maxFileSize, "File is too large. Increase OPENCV_IMGCODECS_WEBP_MAX_FILE_SIZE parameter if you want to process large files");
|
||||
|
||||
fs.read((char*)header, sizeof(header));
|
||||
CV_Assert(fs && "Can't read WEBP_HEADER_SIZE bytes");
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_CheckGE(m_buf.total(), WEBP_HEADER_SIZE, "Buffer is too small");
|
||||
memcpy(header, m_buf.ptr(), sizeof(header));
|
||||
data = m_buf;
|
||||
}
|
||||
|
||||
WebPBitstreamFeatures features;
|
||||
if (VP8_STATUS_OK == WebPGetFeatures(header, sizeof(header), &features))
|
||||
{
|
||||
m_width = features.width;
|
||||
m_height = features.height;
|
||||
|
||||
if (features.has_alpha)
|
||||
{
|
||||
m_type = CV_8UC4;
|
||||
channels = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = CV_8UC3;
|
||||
channels = 3;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebPDecoder::readData(Mat &img)
|
||||
{
|
||||
CV_CheckGE(m_width, 0, ""); CV_CheckGE(m_height, 0, "");
|
||||
|
||||
CV_CheckEQ(img.cols, m_width, "");
|
||||
CV_CheckEQ(img.rows, m_height, "");
|
||||
|
||||
if (m_buf.empty())
|
||||
{
|
||||
fs.seekg(0, std::ios::beg); CV_Assert(fs && "File stream error");
|
||||
data.create(1, validateToInt(fs_size), CV_8UC1);
|
||||
fs.read((char*)data.ptr(), fs_size);
|
||||
CV_Assert(fs && "Can't read file data");
|
||||
fs.close();
|
||||
}
|
||||
CV_Assert(data.type() == CV_8UC1); CV_Assert(data.rows == 1);
|
||||
|
||||
{
|
||||
Mat read_img;
|
||||
CV_CheckType(img.type(), img.type() == CV_8UC1 || img.type() == CV_8UC3 || img.type() == CV_8UC4, "");
|
||||
if (img.type() != m_type)
|
||||
{
|
||||
read_img.create(m_height, m_width, m_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
read_img = img; // copy header
|
||||
}
|
||||
|
||||
uchar* out_data = read_img.ptr();
|
||||
size_t out_data_size = read_img.dataend - out_data;
|
||||
|
||||
uchar *res_ptr = NULL;
|
||||
if (channels == 3)
|
||||
{
|
||||
CV_CheckTypeEQ(read_img.type(), CV_8UC3, "");
|
||||
res_ptr = WebPDecodeBGRInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
}
|
||||
else if (channels == 4)
|
||||
{
|
||||
CV_CheckTypeEQ(read_img.type(), CV_8UC4, "");
|
||||
res_ptr = WebPDecodeBGRAInto(data.ptr(), data.total(), out_data,
|
||||
(int)out_data_size, (int)read_img.step);
|
||||
}
|
||||
|
||||
if (res_ptr != out_data)
|
||||
return false;
|
||||
|
||||
if (read_img.data == img.data && img.type() == m_type)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
else if (img.type() == CV_8UC1)
|
||||
{
|
||||
cvtColor(read_img, img, COLOR_BGR2GRAY);
|
||||
}
|
||||
else if (img.type() == CV_8UC3 && m_type == CV_8UC4)
|
||||
{
|
||||
cvtColor(read_img, img, COLOR_BGRA2BGR);
|
||||
}
|
||||
else if (img.type() == CV_8UC4 && m_type == CV_8UC3)
|
||||
{
|
||||
cvtColor(read_img, img, COLOR_BGR2BGRA);
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WebPEncoder::WebPEncoder()
|
||||
{
|
||||
m_description = "WebP files (*.webp)";
|
||||
m_buf_supported = true;
|
||||
}
|
||||
|
||||
WebPEncoder::~WebPEncoder() { }
|
||||
|
||||
ImageEncoder WebPEncoder::newEncoder() const
|
||||
{
|
||||
return makePtr<WebPEncoder>();
|
||||
}
|
||||
|
||||
bool WebPEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
{
|
||||
CV_CheckDepthEQ(img.depth(), CV_8U, "WebP codec supports 8U images only");
|
||||
|
||||
const int width = img.cols, height = img.rows;
|
||||
|
||||
bool comp_lossless = true;
|
||||
float quality = 100.0f;
|
||||
|
||||
if (params.size() > 1)
|
||||
{
|
||||
if (params[0] == CV_IMWRITE_WEBP_QUALITY)
|
||||
{
|
||||
comp_lossless = false;
|
||||
quality = static_cast<float>(params[1]);
|
||||
if (quality < 1.0f)
|
||||
{
|
||||
quality = 1.0f;
|
||||
}
|
||||
if (quality > 100.0f)
|
||||
{
|
||||
comp_lossless = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int channels = img.channels();
|
||||
CV_Check(channels, channels == 1 || channels == 3 || channels == 4, "");
|
||||
|
||||
const Mat *image = &img;
|
||||
Mat temp;
|
||||
|
||||
if (channels == 1)
|
||||
{
|
||||
cvtColor(*image, temp, COLOR_GRAY2BGR);
|
||||
image = &temp;
|
||||
channels = 3;
|
||||
}
|
||||
|
||||
uint8_t *out = NULL;
|
||||
size_t size = 0;
|
||||
if (comp_lossless)
|
||||
{
|
||||
if (channels == 3)
|
||||
{
|
||||
size = WebPEncodeLosslessBGR(image->ptr(), width, height, (int)image->step, &out);
|
||||
}
|
||||
else if (channels == 4)
|
||||
{
|
||||
size = WebPEncodeLosslessBGRA(image->ptr(), width, height, (int)image->step, &out);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (channels == 3)
|
||||
{
|
||||
size = WebPEncodeBGR(image->ptr(), width, height, (int)image->step, quality, &out);
|
||||
}
|
||||
else if (channels == 4)
|
||||
{
|
||||
size = WebPEncodeBGRA(image->ptr(), width, height, (int)image->step, quality, &out);
|
||||
}
|
||||
}
|
||||
#if WEBP_DECODER_ABI_VERSION >= 0x0206
|
||||
Ptr<uint8_t> out_cleaner(out, WebPFree);
|
||||
#else
|
||||
Ptr<uint8_t> out_cleaner(out, free);
|
||||
#endif
|
||||
|
||||
CV_Assert(size > 0);
|
||||
|
||||
if (m_buf)
|
||||
{
|
||||
m_buf->resize(size);
|
||||
memcpy(&(*m_buf)[0], out, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *fd = fopen(m_filename.c_str(), "wb");
|
||||
if (fd != NULL)
|
||||
{
|
||||
fwrite(out, size, sizeof(uint8_t), fd);
|
||||
fclose(fd); fd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
92
modules/imgcodecs/src/grfmt_webp.hpp
Normal file
92
modules/imgcodecs/src/grfmt_webp.hpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMT_WEBP_H_
|
||||
#define _GRFMT_WEBP_H_
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
|
||||
#ifdef HAVE_WEBP
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
class WebPDecoder CV_FINAL : public BaseImageDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
WebPDecoder();
|
||||
~WebPDecoder() CV_OVERRIDE;
|
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE;
|
||||
bool readHeader() CV_OVERRIDE;
|
||||
|
||||
size_t signatureLength() const CV_OVERRIDE;
|
||||
bool checkSignature( const String& signature) const CV_OVERRIDE;
|
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE;
|
||||
|
||||
protected:
|
||||
std::ifstream fs;
|
||||
size_t fs_size;
|
||||
Mat data;
|
||||
int channels;
|
||||
};
|
||||
|
||||
class WebPEncoder CV_FINAL : public BaseImageEncoder
|
||||
{
|
||||
public:
|
||||
WebPEncoder();
|
||||
~WebPEncoder() CV_OVERRIDE;
|
||||
|
||||
bool write(const Mat& img, const std::vector<int>& params) CV_OVERRIDE;
|
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _GRFMT_WEBP_H_ */
|
||||
62
modules/imgcodecs/src/grfmts.hpp
Normal file
62
modules/imgcodecs/src/grfmts.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _GRFMTS_H_
|
||||
#define _GRFMTS_H_
|
||||
|
||||
#include "grfmt_base.hpp"
|
||||
#include "grfmt_bmp.hpp"
|
||||
#include "grfmt_sunras.hpp"
|
||||
#include "grfmt_jpeg.hpp"
|
||||
#include "grfmt_pxm.hpp"
|
||||
#include "grfmt_pfm.hpp"
|
||||
#include "grfmt_tiff.hpp"
|
||||
#include "grfmt_png.hpp"
|
||||
#include "grfmt_jpeg2000.hpp"
|
||||
#include "grfmt_jpeg2000_openjpeg.hpp"
|
||||
#include "grfmt_exr.hpp"
|
||||
#include "grfmt_webp.hpp"
|
||||
#include "grfmt_hdr.hpp"
|
||||
#include "grfmt_gdal.hpp"
|
||||
#include "grfmt_gdcm.hpp"
|
||||
#include "grfmt_pam.hpp"
|
||||
|
||||
#endif/*_GRFMTS_H_*/
|
||||
63
modules/imgcodecs/src/ios_conversions.mm
Normal file
63
modules/imgcodecs/src/ios_conversions.mm
Normal file
@@ -0,0 +1,63 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#include "apple_conversions.h"
|
||||
|
||||
CV_EXPORTS UIImage* MatToUIImage(const cv::Mat& image);
|
||||
CV_EXPORTS void UIImageToMat(const UIImage* image, cv::Mat& m, bool alphaExist);
|
||||
|
||||
UIImage* MatToUIImage(const cv::Mat& image) {
|
||||
// Creating CGImage from cv::Mat
|
||||
CGImageRef imageRef = MatToCGImage(image);
|
||||
|
||||
// Getting UIImage from CGImage
|
||||
UIImage *uiImage = [UIImage imageWithCGImage:imageRef];
|
||||
CGImageRelease(imageRef);
|
||||
|
||||
return uiImage;
|
||||
}
|
||||
|
||||
void UIImageToMat(const UIImage* image, cv::Mat& m, bool alphaExist) {
|
||||
CGImageRef imageRef = image.CGImage;
|
||||
CGImageToMat(imageRef, m, alphaExist);
|
||||
}
|
||||
957
modules/imgcodecs/src/loadsave.cpp
Normal file
957
modules/imgcodecs/src/loadsave.cpp
Normal file
@@ -0,0 +1,957 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
//
|
||||
// Loading and saving images.
|
||||
//
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "grfmts.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "exif.hpp"
|
||||
#undef min
|
||||
#undef max
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cerrno>
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
#include <opencv2/core/utils/configuration.private.hpp>
|
||||
|
||||
|
||||
/****************************************************************************************\
|
||||
* Image Codecs *
|
||||
\****************************************************************************************/
|
||||
|
||||
namespace cv {
|
||||
|
||||
static const size_t CV_IO_MAX_IMAGE_PARAMS = cv::utils::getConfigurationParameterSizeT("OPENCV_IO_MAX_IMAGE_PARAMS", 50);
|
||||
static const size_t CV_IO_MAX_IMAGE_WIDTH = utils::getConfigurationParameterSizeT("OPENCV_IO_MAX_IMAGE_WIDTH", 1 << 20);
|
||||
static const size_t CV_IO_MAX_IMAGE_HEIGHT = utils::getConfigurationParameterSizeT("OPENCV_IO_MAX_IMAGE_HEIGHT", 1 << 20);
|
||||
static const size_t CV_IO_MAX_IMAGE_PIXELS = utils::getConfigurationParameterSizeT("OPENCV_IO_MAX_IMAGE_PIXELS", 1 << 30);
|
||||
|
||||
static Size validateInputImageSize(const Size& size)
|
||||
{
|
||||
CV_Assert(size.width > 0);
|
||||
CV_Assert(static_cast<size_t>(size.width) <= CV_IO_MAX_IMAGE_WIDTH);
|
||||
CV_Assert(size.height > 0);
|
||||
CV_Assert(static_cast<size_t>(size.height) <= CV_IO_MAX_IMAGE_HEIGHT);
|
||||
uint64 pixels = (uint64)size.width * (uint64)size.height;
|
||||
CV_Assert(pixels <= CV_IO_MAX_IMAGE_PIXELS);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class ByteStreamBuffer: public std::streambuf
|
||||
{
|
||||
public:
|
||||
ByteStreamBuffer(char* base, size_t length)
|
||||
{
|
||||
setg(base, base, base + length);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual pos_type seekoff( off_type offset,
|
||||
std::ios_base::seekdir dir,
|
||||
std::ios_base::openmode ) CV_OVERRIDE
|
||||
{
|
||||
char* whence = eback();
|
||||
if (dir == std::ios_base::cur)
|
||||
{
|
||||
whence = gptr();
|
||||
}
|
||||
else if (dir == std::ios_base::end)
|
||||
{
|
||||
whence = egptr();
|
||||
}
|
||||
char* to = whence + offset;
|
||||
|
||||
// check limits
|
||||
if (to >= eback() && to <= egptr())
|
||||
{
|
||||
setg(eback(), to, egptr());
|
||||
return gptr() - eback();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @struct ImageCodecInitializer
|
||||
*
|
||||
* Container which stores the registered codecs to be used by OpenCV
|
||||
*/
|
||||
struct ImageCodecInitializer
|
||||
{
|
||||
/**
|
||||
* Default Constructor for the ImageCodeInitializer
|
||||
*/
|
||||
ImageCodecInitializer()
|
||||
{
|
||||
/// BMP Support
|
||||
decoders.push_back( makePtr<BmpDecoder>() );
|
||||
encoders.push_back( makePtr<BmpEncoder>() );
|
||||
|
||||
#ifdef HAVE_IMGCODEC_HDR
|
||||
decoders.push_back( makePtr<HdrDecoder>() );
|
||||
encoders.push_back( makePtr<HdrEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_JPEG
|
||||
decoders.push_back( makePtr<JpegDecoder>() );
|
||||
encoders.push_back( makePtr<JpegEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_WEBP
|
||||
decoders.push_back( makePtr<WebPDecoder>() );
|
||||
encoders.push_back( makePtr<WebPEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_IMGCODEC_SUNRASTER
|
||||
decoders.push_back( makePtr<SunRasterDecoder>() );
|
||||
encoders.push_back( makePtr<SunRasterEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_IMGCODEC_PXM
|
||||
decoders.push_back( makePtr<PxMDecoder>() );
|
||||
encoders.push_back( makePtr<PxMEncoder>(PXM_TYPE_AUTO) );
|
||||
encoders.push_back( makePtr<PxMEncoder>(PXM_TYPE_PBM) );
|
||||
encoders.push_back( makePtr<PxMEncoder>(PXM_TYPE_PGM) );
|
||||
encoders.push_back( makePtr<PxMEncoder>(PXM_TYPE_PPM) );
|
||||
decoders.push_back( makePtr<PAMDecoder>() );
|
||||
encoders.push_back( makePtr<PAMEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_IMGCODEC_PFM
|
||||
decoders.push_back( makePtr<PFMDecoder>() );
|
||||
encoders.push_back( makePtr<PFMEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_TIFF
|
||||
decoders.push_back( makePtr<TiffDecoder>() );
|
||||
encoders.push_back( makePtr<TiffEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_PNG
|
||||
decoders.push_back( makePtr<PngDecoder>() );
|
||||
encoders.push_back( makePtr<PngEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_GDCM
|
||||
decoders.push_back( makePtr<DICOMDecoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_JASPER
|
||||
decoders.push_back( makePtr<Jpeg2KDecoder>() );
|
||||
encoders.push_back( makePtr<Jpeg2KEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_OPENJPEG
|
||||
decoders.push_back( makePtr<Jpeg2KJP2OpjDecoder>() );
|
||||
decoders.push_back( makePtr<Jpeg2KJ2KOpjDecoder>() );
|
||||
encoders.push_back( makePtr<Jpeg2KOpjEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_OPENEXR
|
||||
decoders.push_back( makePtr<ExrDecoder>() );
|
||||
encoders.push_back( makePtr<ExrEncoder>() );
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GDAL
|
||||
/// Attach the GDAL Decoder
|
||||
decoders.push_back( makePtr<GdalDecoder>() );
|
||||
#endif/*HAVE_GDAL*/
|
||||
}
|
||||
|
||||
std::vector<ImageDecoder> decoders;
|
||||
std::vector<ImageEncoder> encoders;
|
||||
};
|
||||
|
||||
static
|
||||
ImageCodecInitializer& getCodecs()
|
||||
{
|
||||
#ifdef CV_CXX11
|
||||
static ImageCodecInitializer g_codecs;
|
||||
return g_codecs;
|
||||
#else
|
||||
// C++98 doesn't guarantee correctness of multi-threaded initialization of static global variables
|
||||
// (memory leak here is not critical, use C++11 to avoid that)
|
||||
static ImageCodecInitializer* g_codecs = new ImageCodecInitializer();
|
||||
return *g_codecs;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the decoders
|
||||
*
|
||||
* @param[in] filename File to search
|
||||
*
|
||||
* @return Image decoder to parse image file.
|
||||
*/
|
||||
static ImageDecoder findDecoder( const String& filename ) {
|
||||
|
||||
size_t i, maxlen = 0;
|
||||
|
||||
/// iterate through list of registered codecs
|
||||
ImageCodecInitializer& codecs = getCodecs();
|
||||
for( i = 0; i < codecs.decoders.size(); i++ )
|
||||
{
|
||||
size_t len = codecs.decoders[i]->signatureLength();
|
||||
maxlen = std::max(maxlen, len);
|
||||
}
|
||||
|
||||
/// Open the file
|
||||
FILE* f= fopen( filename.c_str(), "rb" );
|
||||
|
||||
/// in the event of a failure, return an empty image decoder
|
||||
if( !f )
|
||||
return ImageDecoder();
|
||||
|
||||
// read the file signature
|
||||
String signature(maxlen, ' ');
|
||||
maxlen = fread( (void*)signature.c_str(), 1, maxlen, f );
|
||||
fclose(f);
|
||||
signature = signature.substr(0, maxlen);
|
||||
|
||||
/// compare signature against all decoders
|
||||
for( i = 0; i < codecs.decoders.size(); i++ )
|
||||
{
|
||||
if( codecs.decoders[i]->checkSignature(signature) )
|
||||
return codecs.decoders[i]->newDecoder();
|
||||
}
|
||||
|
||||
/// If no decoder was found, return base type
|
||||
return ImageDecoder();
|
||||
}
|
||||
|
||||
static ImageDecoder findDecoder( const Mat& buf )
|
||||
{
|
||||
size_t i, maxlen = 0;
|
||||
|
||||
if( buf.rows*buf.cols < 1 || !buf.isContinuous() )
|
||||
return ImageDecoder();
|
||||
|
||||
ImageCodecInitializer& codecs = getCodecs();
|
||||
for( i = 0; i < codecs.decoders.size(); i++ )
|
||||
{
|
||||
size_t len = codecs.decoders[i]->signatureLength();
|
||||
maxlen = std::max(maxlen, len);
|
||||
}
|
||||
|
||||
String signature(maxlen, ' ');
|
||||
size_t bufSize = buf.rows*buf.cols*buf.elemSize();
|
||||
maxlen = std::min(maxlen, bufSize);
|
||||
memcpy( (void*)signature.c_str(), buf.data, maxlen );
|
||||
|
||||
for( i = 0; i < codecs.decoders.size(); i++ )
|
||||
{
|
||||
if( codecs.decoders[i]->checkSignature(signature) )
|
||||
return codecs.decoders[i]->newDecoder();
|
||||
}
|
||||
|
||||
return ImageDecoder();
|
||||
}
|
||||
|
||||
static ImageEncoder findEncoder( const String& _ext )
|
||||
{
|
||||
if( _ext.size() <= 1 )
|
||||
return ImageEncoder();
|
||||
|
||||
const char* ext = strrchr( _ext.c_str(), '.' );
|
||||
if( !ext )
|
||||
return ImageEncoder();
|
||||
int len = 0;
|
||||
for( ext++; len < 128 && isalnum(ext[len]); len++ )
|
||||
;
|
||||
|
||||
ImageCodecInitializer& codecs = getCodecs();
|
||||
for( size_t i = 0; i < codecs.encoders.size(); i++ )
|
||||
{
|
||||
String description = codecs.encoders[i]->getDescription();
|
||||
const char* descr = strchr( description.c_str(), '(' );
|
||||
|
||||
while( descr )
|
||||
{
|
||||
descr = strchr( descr + 1, '.' );
|
||||
if( !descr )
|
||||
break;
|
||||
int j = 0;
|
||||
for( descr++; j < len && isalnum(descr[j]) ; j++ )
|
||||
{
|
||||
int c1 = tolower(ext[j]);
|
||||
int c2 = tolower(descr[j]);
|
||||
if( c1 != c2 )
|
||||
break;
|
||||
}
|
||||
if( j == len && !isalnum(descr[j]))
|
||||
return codecs.encoders[i]->newEncoder();
|
||||
descr += j;
|
||||
}
|
||||
}
|
||||
|
||||
return ImageEncoder();
|
||||
}
|
||||
|
||||
|
||||
static void ExifTransform(int orientation, Mat& img)
|
||||
{
|
||||
switch( orientation )
|
||||
{
|
||||
case IMAGE_ORIENTATION_TL: //0th row == visual top, 0th column == visual left-hand side
|
||||
//do nothing, the image already has proper orientation
|
||||
break;
|
||||
case IMAGE_ORIENTATION_TR: //0th row == visual top, 0th column == visual right-hand side
|
||||
flip(img, img, 1); //flip horizontally
|
||||
break;
|
||||
case IMAGE_ORIENTATION_BR: //0th row == visual bottom, 0th column == visual right-hand side
|
||||
flip(img, img, -1);//flip both horizontally and vertically
|
||||
break;
|
||||
case IMAGE_ORIENTATION_BL: //0th row == visual bottom, 0th column == visual left-hand side
|
||||
flip(img, img, 0); //flip vertically
|
||||
break;
|
||||
case IMAGE_ORIENTATION_LT: //0th row == visual left-hand side, 0th column == visual top
|
||||
transpose(img, img);
|
||||
break;
|
||||
case IMAGE_ORIENTATION_RT: //0th row == visual right-hand side, 0th column == visual top
|
||||
transpose(img, img);
|
||||
flip(img, img, 1); //flip horizontally
|
||||
break;
|
||||
case IMAGE_ORIENTATION_RB: //0th row == visual right-hand side, 0th column == visual bottom
|
||||
transpose(img, img);
|
||||
flip(img, img, -1); //flip both horizontally and vertically
|
||||
break;
|
||||
case IMAGE_ORIENTATION_LB: //0th row == visual left-hand side, 0th column == visual bottom
|
||||
transpose(img, img);
|
||||
flip(img, img, 0); //flip vertically
|
||||
break;
|
||||
default:
|
||||
//by default the image read has normal (JPEG_ORIENTATION_TL) orientation
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ApplyExifOrientation(ExifEntry_t orientationTag, Mat& img)
|
||||
{
|
||||
int orientation = IMAGE_ORIENTATION_TL;
|
||||
|
||||
if (orientationTag.tag != INVALID_TAG)
|
||||
{
|
||||
orientation = orientationTag.field_u16; //orientation is unsigned short, so check field_u16
|
||||
ExifTransform(orientation, img);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an image into memory and return the information
|
||||
*
|
||||
* @param[in] filename File to load
|
||||
* @param[in] flags Flags
|
||||
* @param[in] hdrtype { LOAD_CVMAT=0,
|
||||
* LOAD_IMAGE=1,
|
||||
* LOAD_MAT=2
|
||||
* }
|
||||
* @param[in] mat Reference to C++ Mat object (If LOAD_MAT)
|
||||
*
|
||||
*/
|
||||
static bool
|
||||
imread_( const String& filename, int flags, Mat& mat )
|
||||
{
|
||||
/// Search for the relevant decoder to handle the imagery
|
||||
ImageDecoder decoder;
|
||||
|
||||
#ifdef HAVE_GDAL
|
||||
if(flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL ){
|
||||
decoder = GdalDecoder().newDecoder();
|
||||
}else{
|
||||
#endif
|
||||
decoder = findDecoder( filename );
|
||||
#ifdef HAVE_GDAL
|
||||
}
|
||||
#endif
|
||||
|
||||
/// if no decoder was found, return nothing.
|
||||
if( !decoder ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scale_denom = 1;
|
||||
if( flags > IMREAD_LOAD_GDAL )
|
||||
{
|
||||
if( flags & IMREAD_REDUCED_GRAYSCALE_2 )
|
||||
scale_denom = 2;
|
||||
else if( flags & IMREAD_REDUCED_GRAYSCALE_4 )
|
||||
scale_denom = 4;
|
||||
else if( flags & IMREAD_REDUCED_GRAYSCALE_8 )
|
||||
scale_denom = 8;
|
||||
}
|
||||
|
||||
/// set the scale_denom in the driver
|
||||
decoder->setScale( scale_denom );
|
||||
|
||||
/// set the filename in the driver
|
||||
decoder->setSource( filename );
|
||||
|
||||
try
|
||||
{
|
||||
// read the header to make sure it succeeds
|
||||
if( !decoder->readHeader() )
|
||||
return 0;
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imread_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imread_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// established the required input image size
|
||||
Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
|
||||
|
||||
// grab the decoded type
|
||||
int type = decoder->type();
|
||||
if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED )
|
||||
{
|
||||
if( (flags & IMREAD_ANYDEPTH) == 0 )
|
||||
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
|
||||
|
||||
if( (flags & IMREAD_COLOR) != 0 ||
|
||||
((flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )
|
||||
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
|
||||
else
|
||||
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
|
||||
}
|
||||
|
||||
mat.create( size.height, size.width, type );
|
||||
|
||||
// read the image data
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
if (decoder->readData(mat))
|
||||
success = true;
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imread_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imread_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
mat.release();
|
||||
return false;
|
||||
}
|
||||
|
||||
if( decoder->setScale( scale_denom ) > 1 ) // if decoder is JpegDecoder then decoder->setScale always returns 1
|
||||
{
|
||||
resize( mat, mat, Size( size.width / scale_denom, size.height / scale_denom ), 0, 0, INTER_LINEAR_EXACT);
|
||||
}
|
||||
|
||||
/// optionally rotate the data if EXIF orientation flag says so
|
||||
if (!mat.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
|
||||
{
|
||||
ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read an image into memory and return the information
|
||||
*
|
||||
* @param[in] filename File to load
|
||||
* @param[in] flags Flags
|
||||
* @param[in] mats Reference to C++ vector<Mat> object to hold the images
|
||||
*
|
||||
*/
|
||||
static bool
|
||||
imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
|
||||
{
|
||||
/// Search for the relevant decoder to handle the imagery
|
||||
ImageDecoder decoder;
|
||||
|
||||
#ifdef HAVE_GDAL
|
||||
if (flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL){
|
||||
decoder = GdalDecoder().newDecoder();
|
||||
}
|
||||
else{
|
||||
#endif
|
||||
decoder = findDecoder(filename);
|
||||
#ifdef HAVE_GDAL
|
||||
}
|
||||
#endif
|
||||
|
||||
/// if no decoder was found, return nothing.
|
||||
if (!decoder){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// set the filename in the driver
|
||||
decoder->setSource(filename);
|
||||
|
||||
// read the header to make sure it succeeds
|
||||
try
|
||||
{
|
||||
// read the header to make sure it succeeds
|
||||
if( !decoder->readHeader() )
|
||||
return 0;
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// grab the decoded type
|
||||
int type = decoder->type();
|
||||
if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED )
|
||||
{
|
||||
if ((flags & IMREAD_ANYDEPTH) == 0)
|
||||
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
|
||||
|
||||
if ((flags & CV_LOAD_IMAGE_COLOR) != 0 ||
|
||||
((flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1))
|
||||
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
|
||||
else
|
||||
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
|
||||
}
|
||||
|
||||
// established the required input image size
|
||||
Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
|
||||
|
||||
// read the image data
|
||||
Mat mat(size.height, size.width, type);
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
if (decoder->readData(mat))
|
||||
success = true;
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
|
||||
}
|
||||
if (!success)
|
||||
break;
|
||||
|
||||
// optionally rotate the data if EXIF' orientation flag says so
|
||||
if( (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
|
||||
{
|
||||
ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
|
||||
}
|
||||
|
||||
mats.push_back(mat);
|
||||
if (!decoder->nextPage())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !mats.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an image
|
||||
*
|
||||
* This function merely calls the actual implementation above and returns itself.
|
||||
*
|
||||
* @param[in] filename File to load
|
||||
* @param[in] flags Flags you wish to set.
|
||||
*/
|
||||
Mat imread( const String& filename, int flags )
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
/// create the basic container
|
||||
Mat img;
|
||||
|
||||
/// load the data
|
||||
imread_( filename, flags, img );
|
||||
|
||||
/// return a reference to the data
|
||||
return img;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a multi-page image
|
||||
*
|
||||
* This function merely calls the actual implementation above and returns itself.
|
||||
*
|
||||
* @param[in] filename File to load
|
||||
* @param[in] mats Reference to C++ vector<Mat> object to hold the images
|
||||
* @param[in] flags Flags you wish to set.
|
||||
*
|
||||
*/
|
||||
bool imreadmulti(const String& filename, std::vector<Mat>& mats, int flags)
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
return imreadmulti_(filename, flags, mats);
|
||||
}
|
||||
|
||||
static bool imwrite_( const String& filename, const std::vector<Mat>& img_vec,
|
||||
const std::vector<int>& params, bool flipv )
|
||||
{
|
||||
bool isMultiImg = img_vec.size() > 1;
|
||||
std::vector<Mat> write_vec;
|
||||
|
||||
ImageEncoder encoder = findEncoder( filename );
|
||||
if( !encoder )
|
||||
CV_Error( Error::StsError, "could not find a writer for the specified extension" );
|
||||
|
||||
for (size_t page = 0; page < img_vec.size(); page++)
|
||||
{
|
||||
Mat image = img_vec[page];
|
||||
CV_Assert(!image.empty());
|
||||
|
||||
CV_Assert( image.channels() == 1 || image.channels() == 3 || image.channels() == 4 );
|
||||
|
||||
Mat temp;
|
||||
if( !encoder->isFormatSupported(image.depth()) )
|
||||
{
|
||||
CV_Assert( encoder->isFormatSupported(CV_8U) );
|
||||
image.convertTo( temp, CV_8U );
|
||||
image = temp;
|
||||
}
|
||||
|
||||
if( flipv )
|
||||
{
|
||||
flip(image, temp, 0);
|
||||
image = temp;
|
||||
}
|
||||
|
||||
write_vec.push_back(image);
|
||||
}
|
||||
|
||||
encoder->setDestination( filename );
|
||||
CV_Assert(params.size() <= CV_IO_MAX_IMAGE_PARAMS*2);
|
||||
bool code = false;
|
||||
try
|
||||
{
|
||||
if (!isMultiImg)
|
||||
code = encoder->write( write_vec[0], params );
|
||||
else
|
||||
code = encoder->writemulti( write_vec, params ); //to be implemented
|
||||
|
||||
if (!code)
|
||||
{
|
||||
FILE* f = fopen( filename.c_str(), "wb" );
|
||||
if ( !f )
|
||||
{
|
||||
if (errno == EACCES)
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "imwrite_('" << filename << "'): can't open file for writing: permission denied");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fclose(f);
|
||||
remove(filename.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imwrite_('" << filename << "'): can't write data: " << e.what() << std::endl << std::flush;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imwrite_('" << filename << "'): can't write data: unknown exception" << std::endl << std::flush;
|
||||
}
|
||||
|
||||
// CV_Assert( code );
|
||||
return code;
|
||||
}
|
||||
|
||||
bool imwrite( const String& filename, InputArray _img,
|
||||
const std::vector<int>& params )
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
CV_Assert(!_img.empty());
|
||||
|
||||
std::vector<Mat> img_vec;
|
||||
if (_img.isMatVector() || _img.isUMatVector())
|
||||
_img.getMatVector(img_vec);
|
||||
else
|
||||
img_vec.push_back(_img.getMat());
|
||||
|
||||
CV_Assert(!img_vec.empty());
|
||||
return imwrite_(filename, img_vec, params, false);
|
||||
}
|
||||
|
||||
static bool
|
||||
imdecode_( const Mat& buf, int flags, Mat& mat )
|
||||
{
|
||||
CV_Assert(!buf.empty());
|
||||
CV_Assert(buf.isContinuous());
|
||||
CV_Assert(buf.checkVector(1, CV_8U) > 0);
|
||||
Mat buf_row = buf.reshape(1, 1); // decoders expects single row, avoid issues with vector columns
|
||||
|
||||
String filename;
|
||||
|
||||
ImageDecoder decoder = findDecoder(buf_row);
|
||||
if( !decoder )
|
||||
return 0;
|
||||
|
||||
int scale_denom = 1;
|
||||
if( flags > IMREAD_LOAD_GDAL )
|
||||
{
|
||||
if( flags & IMREAD_REDUCED_GRAYSCALE_2 )
|
||||
scale_denom = 2;
|
||||
else if( flags & IMREAD_REDUCED_GRAYSCALE_4 )
|
||||
scale_denom = 4;
|
||||
else if( flags & IMREAD_REDUCED_GRAYSCALE_8 )
|
||||
scale_denom = 8;
|
||||
}
|
||||
|
||||
/// set the scale_denom in the driver
|
||||
decoder->setScale( scale_denom );
|
||||
|
||||
if( !decoder->setSource(buf_row) )
|
||||
{
|
||||
filename = tempfile();
|
||||
FILE* f = fopen( filename.c_str(), "wb" );
|
||||
if( !f )
|
||||
return 0;
|
||||
size_t bufSize = buf_row.total()*buf.elemSize();
|
||||
if (fwrite(buf_row.ptr(), 1, bufSize, f) != bufSize)
|
||||
{
|
||||
fclose( f );
|
||||
CV_Error( Error::StsError, "failed to write image data to temporary file" );
|
||||
}
|
||||
if( fclose(f) != 0 )
|
||||
{
|
||||
CV_Error( Error::StsError, "failed to write image data to temporary file" );
|
||||
}
|
||||
decoder->setSource(filename);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
if (decoder->readHeader())
|
||||
success = true;
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imdecode_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imdecode_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
decoder.release();
|
||||
if (!filename.empty())
|
||||
{
|
||||
if (0 != remove(filename.c_str()))
|
||||
{
|
||||
std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// established the required input image size
|
||||
Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
|
||||
|
||||
int type = decoder->type();
|
||||
if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED )
|
||||
{
|
||||
if( (flags & IMREAD_ANYDEPTH) == 0 )
|
||||
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
|
||||
|
||||
if( (flags & IMREAD_COLOR) != 0 ||
|
||||
((flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )
|
||||
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
|
||||
else
|
||||
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
|
||||
}
|
||||
|
||||
mat.create( size.height, size.width, type );
|
||||
|
||||
success = false;
|
||||
try
|
||||
{
|
||||
if (decoder->readData(mat))
|
||||
success = true;
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imdecode_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imdecode_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
|
||||
}
|
||||
|
||||
if (!filename.empty())
|
||||
{
|
||||
if (0 != remove(filename.c_str()))
|
||||
{
|
||||
std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
mat.release();
|
||||
return false;
|
||||
}
|
||||
|
||||
if( decoder->setScale( scale_denom ) > 1 ) // if decoder is JpegDecoder then decoder->setScale always returns 1
|
||||
{
|
||||
resize(mat, mat, Size( size.width / scale_denom, size.height / scale_denom ), 0, 0, INTER_LINEAR_EXACT);
|
||||
}
|
||||
|
||||
/// optionally rotate the data if EXIF' orientation flag says so
|
||||
if (!mat.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED)
|
||||
{
|
||||
ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Mat imdecode( InputArray _buf, int flags )
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
Mat buf = _buf.getMat(), img;
|
||||
imdecode_( buf, flags, img );
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
Mat imdecode( InputArray _buf, int flags, Mat* dst )
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
Mat buf = _buf.getMat(), img;
|
||||
dst = dst ? dst : &img;
|
||||
imdecode_( buf, flags, *dst );
|
||||
|
||||
return *dst;
|
||||
}
|
||||
|
||||
bool imencode( const String& ext, InputArray _image,
|
||||
std::vector<uchar>& buf, const std::vector<int>& params )
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
Mat image = _image.getMat();
|
||||
CV_Assert(!image.empty());
|
||||
|
||||
int channels = image.channels();
|
||||
CV_Assert( channels == 1 || channels == 3 || channels == 4 );
|
||||
|
||||
ImageEncoder encoder = findEncoder( ext );
|
||||
if( !encoder )
|
||||
CV_Error( Error::StsError, "could not find encoder for the specified extension" );
|
||||
|
||||
if( !encoder->isFormatSupported(image.depth()) )
|
||||
{
|
||||
CV_Assert( encoder->isFormatSupported(CV_8U) );
|
||||
Mat temp;
|
||||
image.convertTo(temp, CV_8U);
|
||||
image = temp;
|
||||
}
|
||||
|
||||
bool code;
|
||||
if( encoder->setDestination(buf) )
|
||||
{
|
||||
code = encoder->write(image, params);
|
||||
encoder->throwOnEror();
|
||||
CV_Assert( code );
|
||||
}
|
||||
else
|
||||
{
|
||||
String filename = tempfile();
|
||||
code = encoder->setDestination(filename);
|
||||
CV_Assert( code );
|
||||
|
||||
code = encoder->write(image, params);
|
||||
encoder->throwOnEror();
|
||||
CV_Assert( code );
|
||||
|
||||
FILE* f = fopen( filename.c_str(), "rb" );
|
||||
CV_Assert(f != 0);
|
||||
fseek( f, 0, SEEK_END );
|
||||
long pos = ftell(f);
|
||||
buf.resize((size_t)pos);
|
||||
fseek( f, 0, SEEK_SET );
|
||||
buf.resize(fread( &buf[0], 1, buf.size(), f ));
|
||||
fclose(f);
|
||||
remove(filename.c_str());
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
bool haveImageReader( const String& filename )
|
||||
{
|
||||
ImageDecoder decoder = cv::findDecoder(filename);
|
||||
return !decoder.empty();
|
||||
}
|
||||
|
||||
bool haveImageWriter( const String& filename )
|
||||
{
|
||||
cv::ImageEncoder encoder = cv::findEncoder(filename);
|
||||
return !encoder.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
25
modules/imgcodecs/src/macosx_conversions.mm
Normal file
25
modules/imgcodecs/src/macosx_conversions.mm
Normal file
@@ -0,0 +1,25 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "apple_conversions.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
CV_EXPORTS NSImage* MatToNSImage(const cv::Mat& image);
|
||||
CV_EXPORTS void NSImageToMat(const NSImage* image, cv::Mat& m, bool alphaExist);
|
||||
|
||||
NSImage* MatToNSImage(const cv::Mat& image) {
|
||||
// Creating CGImage from cv::Mat
|
||||
CGImageRef imageRef = MatToCGImage(image);
|
||||
|
||||
// Getting NSImage from CGImage
|
||||
NSImage *nsImage = [[NSImage alloc] initWithCGImage:imageRef size:CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef))];
|
||||
CGImageRelease(imageRef);
|
||||
|
||||
return nsImage;
|
||||
}
|
||||
|
||||
void NSImageToMat(const NSImage* image, cv::Mat& m, bool alphaExist) {
|
||||
CGImageRef imageRef = [image CGImageForProposedRect:NULL context:NULL hints:NULL];
|
||||
CGImageToMat(imageRef, m, alphaExist);
|
||||
}
|
||||
71
modules/imgcodecs/src/precomp.hpp
Normal file
71
modules/imgcodecs/src/precomp.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __IMGCODECS_H_
|
||||
#define __IMGCODECS_H_
|
||||
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/imgcodecs/legacy/constants_c.h"
|
||||
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/core/private.hpp"
|
||||
|
||||
#include "opencv2/imgproc.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined _WIN32 || defined WINCE
|
||||
#include <windows.h>
|
||||
#undef small
|
||||
#undef min
|
||||
#undef max
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#define __BEGIN__ __CV_BEGIN__
|
||||
#define __END__ __CV_END__
|
||||
#define EXIT __CV_EXIT__
|
||||
|
||||
#endif /* __IMGCODECS_H_ */
|
||||
454
modules/imgcodecs/src/rgbe.cpp
Normal file
454
modules/imgcodecs/src/rgbe.cpp
Normal file
@@ -0,0 +1,454 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "rgbe.hpp"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// This file contains code to read and write four byte rgbe file format
|
||||
// developed by Greg Ward. It handles the conversions between rgbe and
|
||||
// pixels consisting of floats. The data is assumed to be an array of floats.
|
||||
// By default there are three floats per pixel in the order red, green, blue.
|
||||
// (RGBE_DATA_??? values control this.) Only the minimal header reading and
|
||||
// writing is implemented. Each routine does error checking and will return
|
||||
// a status value as defined below. This code is intended as a skeleton so
|
||||
// feel free to modify it to suit your needs.
|
||||
|
||||
// Some opencv specific changes have been added:
|
||||
// inline define specified, error handler uses CV_Error,
|
||||
// defines changed to work in bgr color space.
|
||||
//
|
||||
// posted to http://www.graphics.cornell.edu/~bjw/
|
||||
// written by Bruce Walter (bjw@graphics.cornell.edu) 5/26/95
|
||||
// based on code written by Greg Ward
|
||||
|
||||
#define INLINE inline
|
||||
|
||||
/* offsets to red, green, and blue components in a data (float) pixel */
|
||||
#define RGBE_DATA_RED 2
|
||||
#define RGBE_DATA_GREEN 1
|
||||
#define RGBE_DATA_BLUE 0
|
||||
/* number of floats per pixel */
|
||||
#define RGBE_DATA_SIZE 3
|
||||
|
||||
enum rgbe_error_codes {
|
||||
rgbe_read_error,
|
||||
rgbe_write_error,
|
||||
rgbe_format_error,
|
||||
rgbe_memory_error
|
||||
};
|
||||
|
||||
/* default error routine. change this to change error handling */
|
||||
static int rgbe_error(int rgbe_error_code, const char *msg)
|
||||
{
|
||||
switch (rgbe_error_code) {
|
||||
case rgbe_read_error:
|
||||
CV_Error(cv::Error::StsError, "RGBE read error");
|
||||
break;
|
||||
case rgbe_write_error:
|
||||
CV_Error(cv::Error::StsError, "RGBE write error");
|
||||
break;
|
||||
case rgbe_format_error:
|
||||
CV_Error(cv::Error::StsError, cv::String("RGBE bad file format: ") +
|
||||
cv::String(msg));
|
||||
break;
|
||||
default:
|
||||
case rgbe_memory_error:
|
||||
CV_Error(cv::Error::StsError, cv::String("RGBE error: \n") +
|
||||
cv::String(msg));
|
||||
}
|
||||
}
|
||||
|
||||
/* standard conversion from float pixels to rgbe pixels */
|
||||
/* note: you can remove the "inline"s if your compiler complains about it */
|
||||
static INLINE void
|
||||
float2rgbe(unsigned char rgbe[4], float red, float green, float blue)
|
||||
{
|
||||
float v;
|
||||
int e;
|
||||
|
||||
v = red;
|
||||
if (green > v) v = green;
|
||||
if (blue > v) v = blue;
|
||||
if (v < 1e-32) {
|
||||
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
|
||||
}
|
||||
else {
|
||||
v = static_cast<float>(frexp(v,&e) * 256.0/v);
|
||||
rgbe[0] = (unsigned char) (red * v);
|
||||
rgbe[1] = (unsigned char) (green * v);
|
||||
rgbe[2] = (unsigned char) (blue * v);
|
||||
rgbe[3] = (unsigned char) (e + 128);
|
||||
}
|
||||
}
|
||||
|
||||
/* standard conversion from rgbe to float pixels */
|
||||
/* note: Ward uses ldexp(col+0.5,exp-(128+8)). However we wanted pixels */
|
||||
/* in the range [0,1] to map back into the range [0,1]. */
|
||||
static INLINE void
|
||||
rgbe2float(float *red, float *green, float *blue, unsigned char rgbe[4])
|
||||
{
|
||||
float f;
|
||||
|
||||
if (rgbe[3]) { /*nonzero pixel*/
|
||||
f = static_cast<float>(ldexp(1.0,rgbe[3]-(int)(128+8)));
|
||||
*red = rgbe[0] * f;
|
||||
*green = rgbe[1] * f;
|
||||
*blue = rgbe[2] * f;
|
||||
}
|
||||
else
|
||||
*red = *green = *blue = 0.0;
|
||||
}
|
||||
|
||||
/* default minimal header. modify if you want more information in header */
|
||||
int RGBE_WriteHeader(FILE *fp, int width, int height, rgbe_header_info *info)
|
||||
{
|
||||
const char *programtype = "RADIANCE";
|
||||
|
||||
if (info && (info->valid & RGBE_VALID_PROGRAMTYPE))
|
||||
programtype = info->programtype;
|
||||
if (fprintf(fp,"#?%s\n",programtype) < 0)
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
/* The #? is to identify file type, the programtype is optional. */
|
||||
if (info && (info->valid & RGBE_VALID_GAMMA)) {
|
||||
if (fprintf(fp,"GAMMA=%g\n",info->gamma) < 0)
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
}
|
||||
if (info && (info->valid & RGBE_VALID_EXPOSURE)) {
|
||||
if (fprintf(fp,"EXPOSURE=%g\n",info->exposure) < 0)
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
}
|
||||
if (fprintf(fp,"FORMAT=32-bit_rle_rgbe\n\n") < 0)
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
if (fprintf(fp, "-Y %d +X %d\n", height, width) < 0)
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
return RGBE_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
/* minimal header reading. modify if you want to parse more information */
|
||||
int RGBE_ReadHeader(FILE *fp, int *width, int *height, rgbe_header_info *info)
|
||||
{
|
||||
char buf[128];
|
||||
float tempf;
|
||||
int i;
|
||||
|
||||
if (info) {
|
||||
info->valid = 0;
|
||||
info->programtype[0] = 0;
|
||||
info->gamma = info->exposure = 1.0;
|
||||
}
|
||||
|
||||
// 1. read first line
|
||||
if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == NULL)
|
||||
return rgbe_error(rgbe_read_error,NULL);
|
||||
if ((buf[0] != '#')||(buf[1] != '?')) {
|
||||
/* if you want to require the magic token then uncomment the next line */
|
||||
/*return rgbe_error(rgbe_format_error,"bad initial token"); */
|
||||
}
|
||||
else if (info) {
|
||||
info->valid |= RGBE_VALID_PROGRAMTYPE;
|
||||
for(i=0;i<static_cast<int>(sizeof(info->programtype)-1);i++) {
|
||||
if ((buf[i+2] == 0) || isspace(buf[i+2]))
|
||||
break;
|
||||
info->programtype[i] = buf[i+2];
|
||||
}
|
||||
info->programtype[i] = 0;
|
||||
}
|
||||
|
||||
// 2. reading other header lines
|
||||
bool hasFormat = false;
|
||||
for(;;) {
|
||||
if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
|
||||
return rgbe_error(rgbe_read_error,NULL);
|
||||
if (buf[0] == '\n') // end of the header
|
||||
break;
|
||||
else if (buf[0] == '#') // comment
|
||||
continue;
|
||||
else if (strcmp(buf,"FORMAT=32-bit_rle_rgbe\n") == 0)
|
||||
hasFormat = true;
|
||||
else if (info && (sscanf(buf,"GAMMA=%g",&tempf) == 1)) {
|
||||
info->gamma = tempf;
|
||||
info->valid |= RGBE_VALID_GAMMA;
|
||||
}
|
||||
else if (info && (sscanf(buf,"EXPOSURE=%g",&tempf) == 1)) {
|
||||
info->exposure = tempf;
|
||||
info->valid |= RGBE_VALID_EXPOSURE;
|
||||
}
|
||||
}
|
||||
if (strcmp(buf,"\n") != 0)
|
||||
return rgbe_error(rgbe_format_error,
|
||||
"missing blank line after FORMAT specifier");
|
||||
if (!hasFormat)
|
||||
return rgbe_error(rgbe_format_error, "missing FORMAT specifier");
|
||||
|
||||
// 3. reading resolution string
|
||||
if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
|
||||
return rgbe_error(rgbe_read_error,NULL);
|
||||
if (sscanf(buf,"-Y %d +X %d",height,width) < 2)
|
||||
return rgbe_error(rgbe_format_error,"missing image size specifier");
|
||||
return RGBE_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
/* simple write routine that does not use run length encoding */
|
||||
/* These routines can be made faster by allocating a larger buffer and
|
||||
fread-ing and fwrite-ing the data in larger chunks */
|
||||
int RGBE_WritePixels(FILE *fp, float *data, int numpixels)
|
||||
{
|
||||
unsigned char rgbe[4];
|
||||
|
||||
while (numpixels-- > 0) {
|
||||
float2rgbe(rgbe,data[RGBE_DATA_RED],
|
||||
data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
|
||||
data += RGBE_DATA_SIZE;
|
||||
if (fwrite(rgbe, sizeof(rgbe), 1, fp) < 1)
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
}
|
||||
return RGBE_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
/* simple read routine. will not correctly handle run length encoding */
|
||||
int RGBE_ReadPixels(FILE *fp, float *data, int numpixels)
|
||||
{
|
||||
unsigned char rgbe[4];
|
||||
|
||||
while(numpixels-- > 0) {
|
||||
if (fread(rgbe, sizeof(rgbe), 1, fp) < 1)
|
||||
return rgbe_error(rgbe_read_error,NULL);
|
||||
rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],
|
||||
&data[RGBE_DATA_BLUE],rgbe);
|
||||
data += RGBE_DATA_SIZE;
|
||||
}
|
||||
return RGBE_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
/* The code below is only needed for the run-length encoded files. */
|
||||
/* Run length encoding adds considerable complexity but does */
|
||||
/* save some space. For each scanline, each channel (r,g,b,e) is */
|
||||
/* encoded separately for better compression. */
|
||||
|
||||
static int RGBE_WriteBytes_RLE(FILE *fp, unsigned char *data, int numbytes)
|
||||
{
|
||||
#define MINRUNLENGTH 4
|
||||
int cur, beg_run, run_count, old_run_count, nonrun_count;
|
||||
unsigned char buf[2];
|
||||
|
||||
cur = 0;
|
||||
while(cur < numbytes) {
|
||||
beg_run = cur;
|
||||
/* find next run of length at least 4 if one exists */
|
||||
run_count = old_run_count = 0;
|
||||
while((run_count < MINRUNLENGTH) && (beg_run < numbytes)) {
|
||||
beg_run += run_count;
|
||||
old_run_count = run_count;
|
||||
run_count = 1;
|
||||
while( (beg_run + run_count < numbytes) && (run_count < 127)
|
||||
&& (data[beg_run] == data[beg_run + run_count]))
|
||||
run_count++;
|
||||
}
|
||||
/* if data before next big run is a short run then write it as such */
|
||||
if ((old_run_count > 1)&&(old_run_count == beg_run - cur)) {
|
||||
buf[0] = static_cast<unsigned char>(128 + old_run_count); /*write short run*/
|
||||
buf[1] = data[cur];
|
||||
if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1)
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
cur = beg_run;
|
||||
}
|
||||
/* write out bytes until we reach the start of the next run */
|
||||
while(cur < beg_run) {
|
||||
nonrun_count = beg_run - cur;
|
||||
if (nonrun_count > 128)
|
||||
nonrun_count = 128;
|
||||
buf[0] = static_cast<unsigned char>(nonrun_count);
|
||||
if (fwrite(buf,sizeof(buf[0]),1,fp) < 1)
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
if (fwrite(&data[cur],sizeof(data[0])*nonrun_count,1,fp) < 1)
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
cur += nonrun_count;
|
||||
}
|
||||
/* write out next run if one was found */
|
||||
if (run_count >= MINRUNLENGTH) {
|
||||
buf[0] = static_cast<unsigned char>(128 + run_count);
|
||||
buf[1] = data[beg_run];
|
||||
if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1)
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
cur += run_count;
|
||||
}
|
||||
}
|
||||
return RGBE_RETURN_SUCCESS;
|
||||
#undef MINRUNLENGTH
|
||||
}
|
||||
|
||||
int RGBE_WritePixels_RLE(FILE *fp, float *data, int scanline_width,
|
||||
int num_scanlines)
|
||||
{
|
||||
unsigned char rgbe[4];
|
||||
unsigned char *buffer;
|
||||
int i, err;
|
||||
|
||||
if ((scanline_width < 8)||(scanline_width > 0x7fff))
|
||||
/* run length encoding is not allowed so write flat*/
|
||||
return RGBE_WritePixels(fp,data,scanline_width*num_scanlines);
|
||||
buffer = (unsigned char *)malloc(sizeof(unsigned char)*4*scanline_width);
|
||||
if (buffer == NULL)
|
||||
/* no buffer space so write flat */
|
||||
return RGBE_WritePixels(fp,data,scanline_width*num_scanlines);
|
||||
while(num_scanlines-- > 0) {
|
||||
rgbe[0] = 2;
|
||||
rgbe[1] = 2;
|
||||
rgbe[2] = static_cast<unsigned char>(scanline_width >> 8);
|
||||
rgbe[3] = scanline_width & 0xFF;
|
||||
if (fwrite(rgbe, sizeof(rgbe), 1, fp) < 1) {
|
||||
free(buffer);
|
||||
return rgbe_error(rgbe_write_error,NULL);
|
||||
}
|
||||
for(i=0;i<scanline_width;i++) {
|
||||
float2rgbe(rgbe,data[RGBE_DATA_RED],
|
||||
data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
|
||||
buffer[i] = rgbe[0];
|
||||
buffer[i+scanline_width] = rgbe[1];
|
||||
buffer[i+2*scanline_width] = rgbe[2];
|
||||
buffer[i+3*scanline_width] = rgbe[3];
|
||||
data += RGBE_DATA_SIZE;
|
||||
}
|
||||
/* write out each of the four channels separately run length encoded */
|
||||
/* first red, then green, then blue, then exponent */
|
||||
for(i=0;i<4;i++) {
|
||||
if ((err = RGBE_WriteBytes_RLE(fp,&buffer[i*scanline_width],
|
||||
scanline_width)) != RGBE_RETURN_SUCCESS) {
|
||||
free(buffer);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buffer);
|
||||
return RGBE_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
int RGBE_ReadPixels_RLE(FILE *fp, float *data, int scanline_width,
|
||||
int num_scanlines)
|
||||
{
|
||||
unsigned char rgbe[4], *scanline_buffer, *ptr, *ptr_end;
|
||||
int i, count;
|
||||
unsigned char buf[2];
|
||||
|
||||
if ((scanline_width < 8)||(scanline_width > 0x7fff))
|
||||
/* run length encoding is not allowed so read flat*/
|
||||
return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines);
|
||||
scanline_buffer = NULL;
|
||||
/* read in each successive scanline */
|
||||
while(num_scanlines > 0) {
|
||||
if (fread(rgbe,sizeof(rgbe),1,fp) < 1) {
|
||||
free(scanline_buffer);
|
||||
return rgbe_error(rgbe_read_error,NULL);
|
||||
}
|
||||
if ((rgbe[0] != 2)||(rgbe[1] != 2)||(rgbe[2] & 0x80)) {
|
||||
/* this file is not run length encoded */
|
||||
rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],&data[RGBE_DATA_BLUE],rgbe);
|
||||
data += RGBE_DATA_SIZE;
|
||||
free(scanline_buffer);
|
||||
return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines-1);
|
||||
}
|
||||
if ((((int)rgbe[2])<<8 | rgbe[3]) != scanline_width) {
|
||||
free(scanline_buffer);
|
||||
return rgbe_error(rgbe_format_error,"wrong scanline width");
|
||||
}
|
||||
if (scanline_buffer == NULL)
|
||||
scanline_buffer = (unsigned char *)
|
||||
malloc(sizeof(unsigned char)*4*scanline_width);
|
||||
if (scanline_buffer == NULL)
|
||||
return rgbe_error(rgbe_memory_error,"unable to allocate buffer space");
|
||||
|
||||
ptr = &scanline_buffer[0];
|
||||
/* read each of the four channels for the scanline into the buffer */
|
||||
for(i=0;i<4;i++) {
|
||||
ptr_end = &scanline_buffer[(i+1)*scanline_width];
|
||||
while(ptr < ptr_end) {
|
||||
if (fread(buf,sizeof(buf[0])*2,1,fp) < 1) {
|
||||
free(scanline_buffer);
|
||||
return rgbe_error(rgbe_read_error,NULL);
|
||||
}
|
||||
if (buf[0] > 128) {
|
||||
/* a run of the same value */
|
||||
count = buf[0]-128;
|
||||
if ((count == 0)||(count > ptr_end - ptr)) {
|
||||
free(scanline_buffer);
|
||||
return rgbe_error(rgbe_format_error,"bad scanline data");
|
||||
}
|
||||
while(count-- > 0)
|
||||
*ptr++ = buf[1];
|
||||
}
|
||||
else {
|
||||
/* a non-run */
|
||||
count = buf[0];
|
||||
if ((count == 0)||(count > ptr_end - ptr)) {
|
||||
free(scanline_buffer);
|
||||
return rgbe_error(rgbe_format_error,"bad scanline data");
|
||||
}
|
||||
*ptr++ = buf[1];
|
||||
if (--count > 0) {
|
||||
if (fread(ptr,sizeof(*ptr)*count,1,fp) < 1) {
|
||||
free(scanline_buffer);
|
||||
return rgbe_error(rgbe_read_error,NULL);
|
||||
}
|
||||
ptr += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* now convert data from buffer into floats */
|
||||
for(i=0;i<scanline_width;i++) {
|
||||
rgbe[0] = scanline_buffer[i];
|
||||
rgbe[1] = scanline_buffer[i+scanline_width];
|
||||
rgbe[2] = scanline_buffer[i+2*scanline_width];
|
||||
rgbe[3] = scanline_buffer[i+3*scanline_width];
|
||||
rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],
|
||||
&data[RGBE_DATA_BLUE],rgbe);
|
||||
data += RGBE_DATA_SIZE;
|
||||
}
|
||||
num_scanlines--;
|
||||
}
|
||||
free(scanline_buffer);
|
||||
return RGBE_RETURN_SUCCESS;
|
||||
}
|
||||
89
modules/imgcodecs/src/rgbe.hpp
Normal file
89
modules/imgcodecs/src/rgbe.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _RGBE_HDR_H_
|
||||
#define _RGBE_HDR_H_
|
||||
|
||||
// posted to http://www.graphics.cornell.edu/~bjw/
|
||||
// written by Bruce Walter (bjw@graphics.cornell.edu) 5/26/95
|
||||
// based on code written by Greg Ward
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
int valid; /* indicate which fields are valid */
|
||||
char programtype[16]; /* listed at beginning of file to identify it
|
||||
* after "#?". defaults to "RGBE" */
|
||||
float gamma; /* image has already been gamma corrected with
|
||||
* given gamma. defaults to 1.0 (no correction) */
|
||||
float exposure; /* a value of 1.0 in an image corresponds to
|
||||
* <exposure> watts/steradian/m^2.
|
||||
* defaults to 1.0 */
|
||||
} rgbe_header_info;
|
||||
|
||||
/* flags indicating which fields in an rgbe_header_info are valid */
|
||||
#define RGBE_VALID_PROGRAMTYPE 0x01
|
||||
#define RGBE_VALID_GAMMA 0x02
|
||||
#define RGBE_VALID_EXPOSURE 0x04
|
||||
|
||||
/* return codes for rgbe routines */
|
||||
#define RGBE_RETURN_SUCCESS 0
|
||||
#define RGBE_RETURN_FAILURE -1
|
||||
|
||||
/* read or write headers */
|
||||
/* you may set rgbe_header_info to null if you want to */
|
||||
int RGBE_WriteHeader(FILE *fp, int width, int height, rgbe_header_info *info);
|
||||
int RGBE_ReadHeader(FILE *fp, int *width, int *height, rgbe_header_info *info);
|
||||
|
||||
/* read or write pixels */
|
||||
/* can read or write pixels in chunks of any size including single pixels*/
|
||||
int RGBE_WritePixels(FILE *fp, float *data, int numpixels);
|
||||
int RGBE_ReadPixels(FILE *fp, float *data, int numpixels);
|
||||
|
||||
/* read or write run length encoded files */
|
||||
/* must be called to read or write whole scanlines */
|
||||
int RGBE_WritePixels_RLE(FILE *fp, float *data, int scanline_width,
|
||||
int num_scanlines);
|
||||
int RGBE_ReadPixels_RLE(FILE *fp, float *data, int scanline_width,
|
||||
int num_scanlines);
|
||||
|
||||
#endif/*_RGBE_HDR_H_*/
|
||||
609
modules/imgcodecs/src/utils.cpp
Normal file
609
modules/imgcodecs/src/utils.cpp
Normal file
@@ -0,0 +1,609 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace cv {
|
||||
|
||||
int validateToInt(size_t sz)
|
||||
{
|
||||
int valueInt = (int)sz;
|
||||
CV_Assert((size_t)valueInt == sz);
|
||||
return valueInt;
|
||||
}
|
||||
|
||||
#define SCALE 14
|
||||
#define cR (int)(0.299*(1 << SCALE) + 0.5)
|
||||
#define cG (int)(0.587*(1 << SCALE) + 0.5)
|
||||
#define cB ((1 << SCALE) - cR - cG)
|
||||
|
||||
void icvCvt_BGR2Gray_8u_C3C1R( const uchar* bgr, int bgr_step,
|
||||
uchar* gray, int gray_step,
|
||||
Size size, int _swap_rb )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; gray += gray_step )
|
||||
{
|
||||
short cBGR0 = cB;
|
||||
short cBGR2 = cR;
|
||||
if (_swap_rb) std::swap(cBGR0, cBGR2);
|
||||
for( i = 0; i < size.width; i++, bgr += 3 )
|
||||
{
|
||||
int t = descale( bgr[0]*cBGR0 + bgr[1]*cG + bgr[2]*cBGR2, SCALE );
|
||||
gray[i] = (uchar)t;
|
||||
}
|
||||
|
||||
bgr += bgr_step - size.width*3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_BGRA2Gray_16u_CnC1R( const ushort* bgr, int bgr_step,
|
||||
ushort* gray, int gray_step,
|
||||
Size size, int ncn, int _swap_rb )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; gray += gray_step )
|
||||
{
|
||||
short cBGR0 = cB;
|
||||
short cBGR2 = cR;
|
||||
if (_swap_rb) std::swap(cBGR0, cBGR2);
|
||||
for( i = 0; i < size.width; i++, bgr += ncn )
|
||||
{
|
||||
int t = descale( bgr[0]*cBGR0 + bgr[1]*cG + bgr[2]*cBGR2, SCALE );
|
||||
gray[i] = (ushort)t;
|
||||
}
|
||||
|
||||
bgr += bgr_step - size.width*ncn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_BGRA2Gray_8u_C4C1R( const uchar* bgra, int rgba_step,
|
||||
uchar* gray, int gray_step,
|
||||
Size size, int _swap_rb )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; gray += gray_step )
|
||||
{
|
||||
short cBGR0 = cB;
|
||||
short cBGR2 = cR;
|
||||
if (_swap_rb) std::swap(cBGR0, cBGR2);
|
||||
for( i = 0; i < size.width; i++, bgra += 4 )
|
||||
{
|
||||
int t = descale( bgra[0]*cBGR0 + bgra[1]*cG + bgra[2]*cBGR2, SCALE );
|
||||
gray[i] = (uchar)t;
|
||||
}
|
||||
|
||||
bgra += rgba_step - size.width*4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_Gray2BGR_8u_C1C3R( const uchar* gray, int gray_step,
|
||||
uchar* bgr, int bgr_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; gray += gray_step )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgr += 3 )
|
||||
{
|
||||
bgr[0] = bgr[1] = bgr[2] = gray[i];
|
||||
}
|
||||
bgr += bgr_step - size.width*3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step,
|
||||
ushort* bgr, int bgr_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; gray += gray_step/sizeof(gray[0]) )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgr += 3 )
|
||||
{
|
||||
bgr[0] = bgr[1] = bgr[2] = gray[i];
|
||||
}
|
||||
bgr += bgr_step/sizeof(bgr[0]) - size.width*3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_BGRA2BGR_8u_C4C3R( const uchar* bgra, int bgra_step,
|
||||
uchar* bgr, int bgr_step,
|
||||
Size size, int _swap_rb )
|
||||
{
|
||||
int i;
|
||||
int swap_rb = _swap_rb ? 2 : 0;
|
||||
for( ; size.height--; )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgr += 3, bgra += 4 )
|
||||
{
|
||||
uchar t0 = bgra[swap_rb], t1 = bgra[1];
|
||||
bgr[0] = t0; bgr[1] = t1;
|
||||
t0 = bgra[swap_rb^2]; bgr[2] = t0;
|
||||
}
|
||||
bgr += bgr_step - size.width*3;
|
||||
bgra += bgra_step - size.width*4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step,
|
||||
ushort* bgr, int bgr_step,
|
||||
Size size, int _swap_rb )
|
||||
{
|
||||
int i;
|
||||
int swap_rb = _swap_rb ? 2 : 0;
|
||||
for( ; size.height--; )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgr += 3, bgra += 4 )
|
||||
{
|
||||
ushort t0 = bgra[swap_rb], t1 = bgra[1];
|
||||
bgr[0] = t0; bgr[1] = t1;
|
||||
t0 = bgra[swap_rb^2]; bgr[2] = t0;
|
||||
}
|
||||
bgr += bgr_step/sizeof(bgr[0]) - size.width*3;
|
||||
bgra += bgra_step/sizeof(bgra[0]) - size.width*4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_BGRA2RGBA_8u_C4R( const uchar* bgra, int bgra_step,
|
||||
uchar* rgba, int rgba_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgra += 4, rgba += 4 )
|
||||
{
|
||||
uchar t0 = bgra[0], t1 = bgra[1];
|
||||
uchar t2 = bgra[2], t3 = bgra[3];
|
||||
rgba[0] = t2; rgba[1] = t1;
|
||||
rgba[2] = t0; rgba[3] = t3;
|
||||
}
|
||||
bgra += bgra_step - size.width*4;
|
||||
rgba += rgba_step - size.width*4;
|
||||
}
|
||||
}
|
||||
|
||||
void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step,
|
||||
ushort* rgba, int rgba_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgra += 4, rgba += 4 )
|
||||
{
|
||||
ushort t0 = bgra[0], t1 = bgra[1];
|
||||
ushort t2 = bgra[2], t3 = bgra[3];
|
||||
|
||||
rgba[0] = t2; rgba[1] = t1;
|
||||
rgba[2] = t0; rgba[3] = t3;
|
||||
}
|
||||
bgra += bgra_step/sizeof(bgra[0]) - size.width*4;
|
||||
rgba += rgba_step/sizeof(rgba[0]) - size.width*4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_BGR2RGB_8u_C3R( const uchar* bgr, int bgr_step,
|
||||
uchar* rgb, int rgb_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgr += 3, rgb += 3 )
|
||||
{
|
||||
uchar t0 = bgr[0], t1 = bgr[1], t2 = bgr[2];
|
||||
rgb[2] = t0; rgb[1] = t1; rgb[0] = t2;
|
||||
}
|
||||
bgr += bgr_step - size.width*3;
|
||||
rgb += rgb_step - size.width*3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_BGR2RGB_16u_C3R( const ushort* bgr, int bgr_step,
|
||||
ushort* rgb, int rgb_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgr += 3, rgb += 3 )
|
||||
{
|
||||
ushort t0 = bgr[0], t1 = bgr[1], t2 = bgr[2];
|
||||
rgb[2] = t0; rgb[1] = t1; rgb[0] = t2;
|
||||
}
|
||||
bgr += bgr_step - size.width*3;
|
||||
rgb += rgb_step - size.width*3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef unsigned short ushort;
|
||||
|
||||
void icvCvt_BGR5552Gray_8u_C2C1R( const uchar* bgr555, int bgr555_step,
|
||||
uchar* gray, int gray_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; gray += gray_step, bgr555 += bgr555_step )
|
||||
{
|
||||
for( i = 0; i < size.width; i++ )
|
||||
{
|
||||
int t = descale( ((((ushort*)bgr555)[i] << 3) & 0xf8)*cB +
|
||||
((((ushort*)bgr555)[i] >> 2) & 0xf8)*cG +
|
||||
((((ushort*)bgr555)[i] >> 7) & 0xf8)*cR, SCALE );
|
||||
gray[i] = (uchar)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_BGR5652Gray_8u_C2C1R( const uchar* bgr565, int bgr565_step,
|
||||
uchar* gray, int gray_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; gray += gray_step, bgr565 += bgr565_step )
|
||||
{
|
||||
for( i = 0; i < size.width; i++ )
|
||||
{
|
||||
int t = descale( ((((ushort*)bgr565)[i] << 3) & 0xf8)*cB +
|
||||
((((ushort*)bgr565)[i] >> 3) & 0xfc)*cG +
|
||||
((((ushort*)bgr565)[i] >> 8) & 0xf8)*cR, SCALE );
|
||||
gray[i] = (uchar)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_BGR5552BGR_8u_C2C3R( const uchar* bgr555, int bgr555_step,
|
||||
uchar* bgr, int bgr_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; bgr555 += bgr555_step )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgr += 3 )
|
||||
{
|
||||
int t0 = (((ushort*)bgr555)[i] << 3) & 0xf8;
|
||||
int t1 = (((ushort*)bgr555)[i] >> 2) & 0xf8;
|
||||
int t2 = (((ushort*)bgr555)[i] >> 7) & 0xf8;
|
||||
bgr[0] = (uchar)t0; bgr[1] = (uchar)t1; bgr[2] = (uchar)t2;
|
||||
}
|
||||
bgr += bgr_step - size.width*3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step,
|
||||
uchar* bgr, int bgr_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; bgr565 += bgr565_step )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgr += 3 )
|
||||
{
|
||||
int t0 = (((ushort*)bgr565)[i] << 3) & 0xf8;
|
||||
int t1 = (((ushort*)bgr565)[i] >> 3) & 0xfc;
|
||||
int t2 = (((ushort*)bgr565)[i] >> 8) & 0xf8;
|
||||
bgr[0] = (uchar)t0; bgr[1] = (uchar)t1; bgr[2] = (uchar)t2;
|
||||
}
|
||||
bgr += bgr_step - size.width*3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step,
|
||||
uchar* bgr, int bgr_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgr += 3, cmyk += 4 )
|
||||
{
|
||||
int c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
|
||||
c = k - ((255 - c)*k>>8);
|
||||
m = k - ((255 - m)*k>>8);
|
||||
y = k - ((255 - y)*k>>8);
|
||||
bgr[2] = (uchar)c; bgr[1] = (uchar)m; bgr[0] = (uchar)y;
|
||||
}
|
||||
bgr += bgr_step - size.width*3;
|
||||
cmyk += cmyk_step - size.width*4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* cmyk, int cmyk_step,
|
||||
uchar* gray, int gray_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, cmyk += 4 )
|
||||
{
|
||||
int c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
|
||||
c = k - ((255 - c)*k>>8);
|
||||
m = k - ((255 - m)*k>>8);
|
||||
y = k - ((255 - y)*k>>8);
|
||||
int t = descale( y*cB + m*cG + c*cR, SCALE );
|
||||
gray[i] = (uchar)t;
|
||||
}
|
||||
gray += gray_step;
|
||||
cmyk += cmyk_step - size.width*4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CvtPaletteToGray( const PaletteEntry* palette, uchar* grayPalette, int entries )
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < entries; i++ )
|
||||
{
|
||||
icvCvt_BGR2Gray_8u_C3C1R( (uchar*)(palette + i), 0, grayPalette + i, 0, Size(1,1) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FillGrayPalette( PaletteEntry* palette, int bpp, bool negative )
|
||||
{
|
||||
int i, length = 1 << bpp;
|
||||
int xor_mask = negative ? 255 : 0;
|
||||
|
||||
for( i = 0; i < length; i++ )
|
||||
{
|
||||
int val = (i * 255/(length - 1)) ^ xor_mask;
|
||||
palette[i].b = palette[i].g = palette[i].r = (uchar)val;
|
||||
palette[i].a = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool IsColorPalette( PaletteEntry* palette, int bpp )
|
||||
{
|
||||
int i, length = 1 << bpp;
|
||||
|
||||
for( i = 0; i < length; i++ )
|
||||
{
|
||||
if( palette[i].b != palette[i].g ||
|
||||
palette[i].b != palette[i].r )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
uchar* FillUniColor( uchar* data, uchar*& line_end,
|
||||
int step, int width3,
|
||||
int& y, int height,
|
||||
int count3, PaletteEntry clr )
|
||||
{
|
||||
do
|
||||
{
|
||||
uchar* end = data + count3;
|
||||
|
||||
if( end > line_end )
|
||||
end = line_end;
|
||||
|
||||
count3 -= (int)(end - data);
|
||||
|
||||
for( ; data < end; data += 3 )
|
||||
{
|
||||
WRITE_PIX( data, clr );
|
||||
}
|
||||
|
||||
if( data >= line_end )
|
||||
{
|
||||
line_end += step;
|
||||
data = line_end - width3;
|
||||
if( ++y >= height ) break;
|
||||
}
|
||||
}
|
||||
while( count3 > 0 );
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
uchar* FillUniGray( uchar* data, uchar*& line_end,
|
||||
int step, int width,
|
||||
int& y, int height,
|
||||
int count, uchar clr )
|
||||
{
|
||||
do
|
||||
{
|
||||
uchar* end = data + count;
|
||||
|
||||
if( end > line_end )
|
||||
end = line_end;
|
||||
|
||||
count -= (int)(end - data);
|
||||
|
||||
for( ; data < end; data++ )
|
||||
{
|
||||
*data = clr;
|
||||
}
|
||||
|
||||
if( data >= line_end )
|
||||
{
|
||||
line_end += step;
|
||||
data = line_end - width;
|
||||
if( ++y >= height ) break;
|
||||
}
|
||||
}
|
||||
while( count > 0 );
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
uchar* FillColorRow8( uchar* data, uchar* indices, int len, PaletteEntry* palette )
|
||||
{
|
||||
uchar* end = data + len*3;
|
||||
while( (data += 3) < end )
|
||||
{
|
||||
*((PaletteEntry*)(data-3)) = palette[*indices++];
|
||||
}
|
||||
PaletteEntry clr = palette[indices[0]];
|
||||
WRITE_PIX( data - 3, clr );
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
uchar* FillGrayRow8( uchar* data, uchar* indices, int len, uchar* palette )
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < len; i++ )
|
||||
{
|
||||
data[i] = palette[indices[i]];
|
||||
}
|
||||
return data + len;
|
||||
}
|
||||
|
||||
|
||||
uchar* FillColorRow4( uchar* data, uchar* indices, int len, PaletteEntry* palette )
|
||||
{
|
||||
uchar* end = data + len*3;
|
||||
|
||||
while( (data += 6) < end )
|
||||
{
|
||||
int idx = *indices++;
|
||||
*((PaletteEntry*)(data-6)) = palette[idx >> 4];
|
||||
*((PaletteEntry*)(data-3)) = palette[idx & 15];
|
||||
}
|
||||
|
||||
int idx = indices[0];
|
||||
PaletteEntry clr = palette[idx >> 4];
|
||||
WRITE_PIX( data - 6, clr );
|
||||
|
||||
if( data == end )
|
||||
{
|
||||
clr = palette[idx & 15];
|
||||
WRITE_PIX( data - 3, clr );
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
uchar* FillGrayRow4( uchar* data, uchar* indices, int len, uchar* palette )
|
||||
{
|
||||
uchar* end = data + len;
|
||||
while( (data += 2) < end )
|
||||
{
|
||||
int idx = *indices++;
|
||||
data[-2] = palette[idx >> 4];
|
||||
data[-1] = palette[idx & 15];
|
||||
}
|
||||
|
||||
int idx = indices[0];
|
||||
uchar clr = palette[idx >> 4];
|
||||
data[-2] = clr;
|
||||
|
||||
if( data == end )
|
||||
{
|
||||
clr = palette[idx & 15];
|
||||
data[-1] = clr;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
uchar* FillColorRow1( uchar* data, uchar* indices, int len, PaletteEntry* palette )
|
||||
{
|
||||
uchar* end = data + len*3;
|
||||
|
||||
const PaletteEntry p0 = palette[0], p1 = palette[1];
|
||||
|
||||
while( (data += 24) < end )
|
||||
{
|
||||
int idx = *indices++;
|
||||
*((PaletteEntry*)(data - 24)) = (idx & 128) ? p1 : p0;
|
||||
*((PaletteEntry*)(data - 21)) = (idx & 64) ? p1 : p0;
|
||||
*((PaletteEntry*)(data - 18)) = (idx & 32) ? p1 : p0;
|
||||
*((PaletteEntry*)(data - 15)) = (idx & 16) ? p1 : p0;
|
||||
*((PaletteEntry*)(data - 12)) = (idx & 8) ? p1 : p0;
|
||||
*((PaletteEntry*)(data - 9)) = (idx & 4) ? p1 : p0;
|
||||
*((PaletteEntry*)(data - 6)) = (idx & 2) ? p1 : p0;
|
||||
*((PaletteEntry*)(data - 3)) = (idx & 1) ? p1 : p0;
|
||||
}
|
||||
|
||||
int idx = indices[0];
|
||||
for( data -= 24; data < end; data += 3, idx += idx )
|
||||
{
|
||||
const PaletteEntry clr = (idx & 128) ? p1 : p0;
|
||||
WRITE_PIX( data, clr );
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
uchar* FillGrayRow1( uchar* data, uchar* indices, int len, uchar* palette )
|
||||
{
|
||||
uchar* end = data + len;
|
||||
|
||||
const uchar p0 = palette[0], p1 = palette[1];
|
||||
|
||||
while( (data += 8) < end )
|
||||
{
|
||||
int idx = *indices++;
|
||||
*((uchar*)(data - 8)) = (idx & 128) ? p1 : p0;
|
||||
*((uchar*)(data - 7)) = (idx & 64) ? p1 : p0;
|
||||
*((uchar*)(data - 6)) = (idx & 32) ? p1 : p0;
|
||||
*((uchar*)(data - 5)) = (idx & 16) ? p1 : p0;
|
||||
*((uchar*)(data - 4)) = (idx & 8) ? p1 : p0;
|
||||
*((uchar*)(data - 3)) = (idx & 4) ? p1 : p0;
|
||||
*((uchar*)(data - 2)) = (idx & 2) ? p1 : p0;
|
||||
*((uchar*)(data - 1)) = (idx & 1) ? p1 : p0;
|
||||
}
|
||||
|
||||
int idx = indices[0];
|
||||
for( data -= 8; data < end; data++, idx += idx )
|
||||
{
|
||||
data[0] = (idx & 128) ? p1 : p0;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
143
modules/imgcodecs/src/utils.hpp
Normal file
143
modules/imgcodecs/src/utils.hpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
namespace cv {
|
||||
|
||||
int validateToInt(size_t step);
|
||||
|
||||
template <typename _Tp> static inline
|
||||
size_t safeCastToSizeT(const _Tp v_origin, const char* msg)
|
||||
{
|
||||
const size_t value_cast = (size_t)v_origin;
|
||||
if ((_Tp)value_cast != v_origin)
|
||||
CV_Error(cv::Error::StsError, msg ? msg : "Can't cast value into size_t");
|
||||
return value_cast;
|
||||
}
|
||||
|
||||
struct PaletteEntry
|
||||
{
|
||||
unsigned char b, g, r, a;
|
||||
};
|
||||
|
||||
#define WRITE_PIX( ptr, clr ) \
|
||||
(((uchar*)(ptr))[0] = (clr).b, \
|
||||
((uchar*)(ptr))[1] = (clr).g, \
|
||||
((uchar*)(ptr))[2] = (clr).r)
|
||||
|
||||
#define descale(x,n) (((x) + (1 << ((n)-1))) >> (n))
|
||||
#define saturate(x) (uchar)(((x) & ~255) == 0 ? (x) : ~((x)>>31))
|
||||
|
||||
void icvCvt_BGR2Gray_8u_C3C1R( const uchar* bgr, int bgr_step,
|
||||
uchar* gray, int gray_step,
|
||||
Size size, int swap_rb=0 );
|
||||
void icvCvt_BGRA2Gray_8u_C4C1R( const uchar* bgra, int bgra_step,
|
||||
uchar* gray, int gray_step,
|
||||
Size size, int swap_rb=0 );
|
||||
void icvCvt_BGRA2Gray_16u_CnC1R( const ushort* bgra, int bgra_step,
|
||||
ushort* gray, int gray_step,
|
||||
Size size, int ncn, int swap_rb=0 );
|
||||
|
||||
void icvCvt_Gray2BGR_8u_C1C3R( const uchar* gray, int gray_step,
|
||||
uchar* bgr, int bgr_step, Size size );
|
||||
void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step,
|
||||
ushort* bgr, int bgr_step, Size size );
|
||||
|
||||
void icvCvt_BGRA2BGR_8u_C4C3R( const uchar* bgra, int bgra_step,
|
||||
uchar* bgr, int bgr_step,
|
||||
Size size, int swap_rb=0 );
|
||||
void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step,
|
||||
ushort* bgr, int bgr_step,
|
||||
Size size, int _swap_rb );
|
||||
|
||||
void icvCvt_BGR2RGB_8u_C3R( const uchar* bgr, int bgr_step,
|
||||
uchar* rgb, int rgb_step, Size size );
|
||||
#define icvCvt_RGB2BGR_8u_C3R icvCvt_BGR2RGB_8u_C3R
|
||||
void icvCvt_BGR2RGB_16u_C3R( const ushort* bgr, int bgr_step,
|
||||
ushort* rgb, int rgb_step, Size size );
|
||||
#define icvCvt_RGB2BGR_16u_C3R icvCvt_BGR2RGB_16u_C3R
|
||||
|
||||
void icvCvt_BGRA2RGBA_8u_C4R( const uchar* bgra, int bgra_step,
|
||||
uchar* rgba, int rgba_step, Size size );
|
||||
#define icvCvt_RGBA2BGRA_8u_C4R icvCvt_BGRA2RGBA_8u_C4R
|
||||
|
||||
void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step,
|
||||
ushort* rgba, int rgba_step, Size size );
|
||||
#define icvCvt_RGBA2BGRA_16u_C4R icvCvt_BGRA2RGBA_16u_C4R
|
||||
|
||||
void icvCvt_BGR5552Gray_8u_C2C1R( const uchar* bgr555, int bgr555_step,
|
||||
uchar* gray, int gray_step, Size size );
|
||||
void icvCvt_BGR5652Gray_8u_C2C1R( const uchar* bgr565, int bgr565_step,
|
||||
uchar* gray, int gray_step, Size size );
|
||||
void icvCvt_BGR5552BGR_8u_C2C3R( const uchar* bgr555, int bgr555_step,
|
||||
uchar* bgr, int bgr_step, Size size );
|
||||
void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step,
|
||||
uchar* bgr, int bgr_step, Size size );
|
||||
void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step,
|
||||
uchar* bgr, int bgr_step, Size size );
|
||||
void icvCvt_CMYK2Gray_8u_C4C1R( const uchar* ycck, int ycck_step,
|
||||
uchar* gray, int gray_step, Size size );
|
||||
|
||||
void FillGrayPalette( PaletteEntry* palette, int bpp, bool negative = false );
|
||||
bool IsColorPalette( PaletteEntry* palette, int bpp );
|
||||
void CvtPaletteToGray( const PaletteEntry* palette, uchar* grayPalette, int entries );
|
||||
uchar* FillUniColor( uchar* data, uchar*& line_end, int step, int width3,
|
||||
int& y, int height, int count3, PaletteEntry clr );
|
||||
uchar* FillUniGray( uchar* data, uchar*& line_end, int step, int width3,
|
||||
int& y, int height, int count3, uchar clr );
|
||||
|
||||
uchar* FillColorRow8( uchar* data, uchar* indices, int len, PaletteEntry* palette );
|
||||
uchar* FillGrayRow8( uchar* data, uchar* indices, int len, uchar* palette );
|
||||
uchar* FillColorRow4( uchar* data, uchar* indices, int len, PaletteEntry* palette );
|
||||
uchar* FillGrayRow4( uchar* data, uchar* indices, int len, uchar* palette );
|
||||
uchar* FillColorRow1( uchar* data, uchar* indices, int len, PaletteEntry* palette );
|
||||
uchar* FillGrayRow1( uchar* data, uchar* indices, int len, uchar* palette );
|
||||
|
||||
CV_INLINE bool isBigEndian( void )
|
||||
{
|
||||
return (((const int*)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif/*_UTILS_H_*/
|
||||
51
modules/imgcodecs/test/test_common.cpp
Normal file
51
modules/imgcodecs/test/test_common.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
#include "test_common.hpp"
|
||||
|
||||
namespace opencv_test {
|
||||
|
||||
static
|
||||
Mat generateTestImageBGR_()
|
||||
{
|
||||
Size sz(640, 480);
|
||||
Mat result(sz, CV_8UC3, Scalar::all(0));
|
||||
|
||||
const string fname = cvtest::findDataFile("../cv/shared/baboon.png");
|
||||
Mat image = imread(fname, IMREAD_COLOR);
|
||||
CV_Assert(!image.empty());
|
||||
CV_CheckEQ(image.size(), Size(512, 512), "");
|
||||
Rect roi((640-512) / 2, 0, 512, 480);
|
||||
image(Rect(0, 0, 512, 480)).copyTo(result(roi));
|
||||
result(Rect(0, 0, 5, 5)).setTo(Scalar(0, 0, 255)); // R
|
||||
result(Rect(5, 0, 5, 5)).setTo(Scalar(0, 255, 0)); // G
|
||||
result(Rect(10, 0, 5, 5)).setTo(Scalar(255, 0, 0)); // B
|
||||
result(Rect(0, 5, 5, 5)).setTo(Scalar(128, 128, 128)); // gray
|
||||
//imshow("test_image", result); waitKey();
|
||||
return result;
|
||||
}
|
||||
Mat generateTestImageBGR()
|
||||
{
|
||||
static Mat image = generateTestImageBGR_(); // initialize once
|
||||
CV_Assert(!image.empty());
|
||||
return image;
|
||||
}
|
||||
|
||||
static
|
||||
Mat generateTestImageGrayscale_()
|
||||
{
|
||||
Mat imageBGR = generateTestImageBGR();
|
||||
CV_Assert(!imageBGR.empty());
|
||||
|
||||
Mat result;
|
||||
cvtColor(imageBGR, result, COLOR_BGR2GRAY);
|
||||
return result;
|
||||
}
|
||||
Mat generateTestImageGrayscale()
|
||||
{
|
||||
static Mat image = generateTestImageGrayscale_(); // initialize once
|
||||
return image;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
15
modules/imgcodecs/test/test_common.hpp
Normal file
15
modules/imgcodecs/test/test_common.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_TEST_IMGCODECS_COMMON_HPP
|
||||
#define OPENCV_TEST_IMGCODECS_COMMON_HPP
|
||||
|
||||
namespace opencv_test {
|
||||
|
||||
Mat generateTestImageBGR();
|
||||
Mat generateTestImageGrayscale();
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // OPENCV_TEST_IMGCODECS_COMMON_HPP
|
||||
308
modules/imgcodecs/test/test_exr.impl.hpp
Normal file
308
modules/imgcodecs/test/test_exr.impl.hpp
Normal file
@@ -0,0 +1,308 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
//#define GENERATE_DATA
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
size_t getFileSize(const string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename.c_str(), std::ios::in | std::ios::binary);
|
||||
if (ifs.is_open())
|
||||
{
|
||||
ifs.seekg(0, std::ios::end);
|
||||
return (size_t)ifs.tellg();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, readWrite_32FC1)
|
||||
{ // Y channels
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test32FC1.exr";
|
||||
const string filenameOutput = cv::tempfile(".exr");
|
||||
#ifndef GENERATE_DATA
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
#else
|
||||
const Size sz(64, 32);
|
||||
Mat img(sz, CV_32FC1, Scalar(0.5, 0.1, 1));
|
||||
img(Rect(10, 5, sz.width - 30, sz.height - 20)).setTo(Scalar(1, 0, 0));
|
||||
ASSERT_TRUE(cv::imwrite(filenameInput, img));
|
||||
#endif
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC1,img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
|
||||
// Check generated file size to ensure that it's compressed with proper options
|
||||
ASSERT_EQ(396u, getFileSize(filenameOutput));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, readWrite_32FC3)
|
||||
{ // RGB channels
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test32FC3.exr";
|
||||
const string filenameOutput = cv::tempfile(".exr");
|
||||
#ifndef GENERATE_DATA
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
#else
|
||||
const Size sz(64, 32);
|
||||
Mat img(sz, CV_32FC3, Scalar(0.5, 0.1, 1));
|
||||
img(Rect(10, 5, sz.width - 30, sz.height - 20)).setTo(Scalar(1, 0, 0));
|
||||
ASSERT_TRUE(cv::imwrite(filenameInput, img));
|
||||
#endif
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC3, img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
|
||||
TEST(Imgcodecs_EXR, readWrite_32FC1_half)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test32FC1_half.exr";
|
||||
const string filenameOutput = cv::tempfile(".exr");
|
||||
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_EXR_TYPE);
|
||||
params.push_back(IMWRITE_EXR_TYPE_HALF);
|
||||
|
||||
#ifndef GENERATE_DATA
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
#else
|
||||
const Size sz(64, 32);
|
||||
Mat img(sz, CV_32FC1, Scalar(0.5, 0.1, 1));
|
||||
img(Rect(10, 5, sz.width - 30, sz.height - 20)).setTo(Scalar(1, 0, 0));
|
||||
ASSERT_TRUE(cv::imwrite(filenameInput, img, params));
|
||||
#endif
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC1,img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img, params));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, readWrite_32FC3_half)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test32FC3_half.exr";
|
||||
const string filenameOutput = cv::tempfile(".exr");
|
||||
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_EXR_TYPE);
|
||||
params.push_back(IMWRITE_EXR_TYPE_HALF);
|
||||
|
||||
#ifndef GENERATE_DATA
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
#else
|
||||
const Size sz(64, 32);
|
||||
Mat img(sz, CV_32FC3, Scalar(0.5, 0.1, 1));
|
||||
img(Rect(10, 5, sz.width - 30, sz.height - 20)).setTo(Scalar(1, 0, 0));
|
||||
ASSERT_TRUE(cv::imwrite(filenameInput, img, params));
|
||||
#endif
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC3, img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img, params));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, readWrite_32FC1_PIZ)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test32FC1.exr";
|
||||
const string filenameOutput = cv::tempfile(".exr");
|
||||
|
||||
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC1, img.type());
|
||||
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_EXR_COMPRESSION);
|
||||
params.push_back(IMWRITE_EXR_COMPRESSION_PIZ);
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img, params));
|
||||
// Check generated file size to ensure that it's compressed with proper options
|
||||
ASSERT_EQ(849u, getFileSize(filenameOutput));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
// Note: YC to GRAYSCALE (IMREAD_GRAYSCALE | IMREAD_ANYDEPTH)
|
||||
// outputs a black image,
|
||||
// as does Y to RGB (IMREAD_COLOR | IMREAD_ANYDEPTH).
|
||||
// This behavoir predates adding EXR alpha support issue
|
||||
// 16115.
|
||||
|
||||
TEST(Imgcodecs_EXR, read_YA_ignore_alpha)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_YA.exr";
|
||||
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_GRAYSCALE | IMREAD_ANYDEPTH);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC1, img.type());
|
||||
|
||||
// Writing Y covered by test 32FC1
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, read_YA_unchanged)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_YA.exr";
|
||||
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC2, img.type());
|
||||
|
||||
// Cannot test writing, 2 channel writing not suppported by loadsave
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, read_YC_changeDepth)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_YRYBY.exr";
|
||||
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_COLOR);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_8UC3, img.type());
|
||||
|
||||
// Cannot test writing, EXR encoder doesn't support 8U depth
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, readwrite_YCA_ignore_alpha)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_YRYBYA.exr";
|
||||
const string filenameOutput = cv::tempfile(".exr");
|
||||
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_COLOR | IMREAD_ANYDEPTH);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC3, img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, read_YC_unchanged)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_YRYBY.exr";
|
||||
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC3, img.type());
|
||||
|
||||
// Writing YC covered by test readwrite_YCA_ignore_alpha
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, readwrite_YCA_unchanged)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_YRYBYA.exr";
|
||||
const string filenameOutput = cv::tempfile(".exr");
|
||||
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC4, img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, readwrite_RGBA_togreyscale)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_GeneratedRGBA.exr";
|
||||
const string filenameOutput = cv::tempfile(".exr");
|
||||
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_GRAYSCALE | IMREAD_ANYDEPTH);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC1, img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, read_RGBA_ignore_alpha)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_GeneratedRGBA.exr";
|
||||
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_COLOR | IMREAD_ANYDEPTH);
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC3, img.type());
|
||||
|
||||
// Writing RGB covered by test 32FC3
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_EXR, read_RGBA_unchanged)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test_GeneratedRGBA.exr";
|
||||
const string filenameOutput = cv::tempfile(".exr");
|
||||
|
||||
#ifndef GENERATE_DATA
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
#else
|
||||
const Size sz(64, 32);
|
||||
Mat img(sz, CV_32FC4, Scalar(0.5, 0.1, 1, 1));
|
||||
img(Rect(10, 5, sz.width - 30, sz.height - 20)).setTo(Scalar(1, 0, 0, 1));
|
||||
img(Rect(10, 20, sz.width - 30, sz.height - 20)).setTo(Scalar(1, 1, 0, 0));
|
||||
ASSERT_TRUE(cv::imwrite(filenameInput, img));
|
||||
#endif
|
||||
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC4, img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
397
modules/imgcodecs/test/test_grfmt.cpp
Normal file
397
modules/imgcodecs/test/test_grfmt.cpp
Normal file
@@ -0,0 +1,397 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef tuple<string, int> File_Mode;
|
||||
typedef testing::TestWithParam<File_Mode> Imgcodecs_FileMode;
|
||||
|
||||
TEST_P(Imgcodecs_FileMode, regression)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + get<0>(GetParam());
|
||||
const int mode = get<1>(GetParam());
|
||||
|
||||
const Mat single = imread(filename, mode);
|
||||
ASSERT_FALSE(single.empty());
|
||||
|
||||
vector<Mat> pages;
|
||||
ASSERT_TRUE(imreadmulti(filename, pages, mode));
|
||||
ASSERT_FALSE(pages.empty());
|
||||
const Mat page = pages[0];
|
||||
ASSERT_FALSE(page.empty());
|
||||
|
||||
EXPECT_EQ(page.channels(), single.channels());
|
||||
EXPECT_EQ(page.depth(), single.depth());
|
||||
EXPECT_EQ(page.size().height, single.size().height);
|
||||
EXPECT_EQ(page.size().width, single.size().width);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), page, single);
|
||||
}
|
||||
|
||||
const string all_images[] =
|
||||
{
|
||||
#if (defined(HAVE_JASPER) && defined(OPENCV_IMGCODECS_ENABLE_JASPER_TESTS)) \
|
||||
|| defined(HAVE_OPENJPEG)
|
||||
"readwrite/Rome.jp2",
|
||||
"readwrite/Bretagne2.jp2",
|
||||
"readwrite/Bretagne2.jp2",
|
||||
"readwrite/Grey.jp2",
|
||||
"readwrite/Grey.jp2",
|
||||
"readwrite/balloon.j2c",
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GDCM
|
||||
"readwrite/int16-mono1.dcm",
|
||||
"readwrite/uint8-mono2.dcm",
|
||||
"readwrite/uint16-mono2.dcm",
|
||||
"readwrite/uint8-rgb.dcm",
|
||||
#endif
|
||||
"readwrite/color_palette_alpha.png",
|
||||
"readwrite/multipage.tif",
|
||||
"readwrite/ordinary.bmp",
|
||||
"readwrite/rle8.bmp",
|
||||
"readwrite/test_1_c1.jpg",
|
||||
#ifdef HAVE_IMGCODEC_HDR
|
||||
"readwrite/rle.hdr"
|
||||
#endif
|
||||
};
|
||||
|
||||
const int basic_modes[] =
|
||||
{
|
||||
IMREAD_UNCHANGED,
|
||||
IMREAD_GRAYSCALE,
|
||||
IMREAD_COLOR,
|
||||
IMREAD_ANYDEPTH,
|
||||
IMREAD_ANYCOLOR
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(All, Imgcodecs_FileMode,
|
||||
testing::Combine(
|
||||
testing::ValuesIn(all_images),
|
||||
testing::ValuesIn(basic_modes)));
|
||||
|
||||
// GDAL does not support "hdr", "dcm" and has problems with JPEG2000 files (jp2, j2c)
|
||||
struct notForGDAL {
|
||||
bool operator()(const string &name) const {
|
||||
const string &ext = name.substr(name.size() - 3, 3);
|
||||
return ext == "hdr" || ext == "dcm" || ext == "jp2" || ext == "j2c" ||
|
||||
name.find("rle8.bmp") != std::string::npos;
|
||||
}
|
||||
};
|
||||
|
||||
inline vector<string> gdal_images()
|
||||
{
|
||||
vector<string> res;
|
||||
std::back_insert_iterator< vector<string> > it(res);
|
||||
std::remove_copy_if(all_images, all_images + sizeof(all_images)/sizeof(all_images[0]), it, notForGDAL());
|
||||
return res;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(GDAL, Imgcodecs_FileMode,
|
||||
testing::Combine(
|
||||
testing::ValuesIn(gdal_images()),
|
||||
testing::Values(IMREAD_LOAD_GDAL)));
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
typedef tuple<string, Size> Ext_Size;
|
||||
typedef testing::TestWithParam<Ext_Size> Imgcodecs_ExtSize;
|
||||
|
||||
TEST_P(Imgcodecs_ExtSize, write_imageseq)
|
||||
{
|
||||
const string ext = get<0>(GetParam());
|
||||
const Size size = get<1>(GetParam());
|
||||
const Point2i center = Point2i(size.width / 2, size.height / 2);
|
||||
const int radius = std::min(size.height, size.width / 4);
|
||||
|
||||
for (int cn = 1; cn <= 4; cn++)
|
||||
{
|
||||
SCOPED_TRACE(format("channels %d", cn));
|
||||
std::vector<int> parameters;
|
||||
if (cn == 2)
|
||||
continue;
|
||||
if (cn == 4 && ext != ".tiff")
|
||||
continue;
|
||||
if (cn > 1 && (ext == ".pbm" || ext == ".pgm"))
|
||||
continue;
|
||||
if (cn != 3 && ext == ".ppm")
|
||||
continue;
|
||||
string filename = cv::tempfile(format("%d%s", cn, ext.c_str()).c_str());
|
||||
|
||||
Mat img_gt(size, CV_MAKETYPE(CV_8U, cn), Scalar::all(0));
|
||||
circle(img_gt, center, radius, Scalar::all(255));
|
||||
|
||||
#if 1
|
||||
if (ext == ".pbm" || ext == ".pgm" || ext == ".ppm")
|
||||
{
|
||||
parameters.push_back(IMWRITE_PXM_BINARY);
|
||||
parameters.push_back(0);
|
||||
}
|
||||
#endif
|
||||
ASSERT_TRUE(imwrite(filename, img_gt, parameters));
|
||||
Mat img = imread(filename, IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
EXPECT_EQ(img.size(), img.size());
|
||||
EXPECT_EQ(img.type(), img.type());
|
||||
EXPECT_EQ(cn, img.channels());
|
||||
|
||||
|
||||
if (ext == ".jpg")
|
||||
{
|
||||
// JPEG format does not provide 100% accuracy
|
||||
// using fuzzy image comparison
|
||||
double n = cvtest::norm(img, img_gt, NORM_L1);
|
||||
double expected = 0.07 * img.size().area();
|
||||
EXPECT_LT(n, expected);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(10, 0), img, img_gt);
|
||||
}
|
||||
else if (ext == ".pfm")
|
||||
{
|
||||
img_gt.convertTo(img_gt, CV_MAKETYPE(CV_32F, img.channels()));
|
||||
double n = cvtest::norm(img, img_gt, NORM_L2);
|
||||
EXPECT_LT(n, 1.);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, img_gt);
|
||||
}
|
||||
else
|
||||
{
|
||||
double n = cvtest::norm(img, img_gt, NORM_L2);
|
||||
EXPECT_LT(n, 1.);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, img_gt);
|
||||
}
|
||||
|
||||
#if 0
|
||||
imshow("loaded", img);
|
||||
waitKey(0);
|
||||
#else
|
||||
EXPECT_EQ(0, remove(filename.c_str()));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
const string all_exts[] =
|
||||
{
|
||||
#ifdef HAVE_PNG
|
||||
".png",
|
||||
#endif
|
||||
#ifdef HAVE_TIFF
|
||||
".tiff",
|
||||
#endif
|
||||
#ifdef HAVE_JPEG
|
||||
".jpg",
|
||||
#endif
|
||||
".bmp",
|
||||
#ifdef HAVE_IMGCODEC_PXM
|
||||
".pam",
|
||||
".ppm",
|
||||
".pgm",
|
||||
".pbm",
|
||||
".pnm",
|
||||
#endif
|
||||
#ifdef HAVE_IMGCODEC_PFM
|
||||
".pfm",
|
||||
#endif
|
||||
};
|
||||
|
||||
vector<Size> all_sizes()
|
||||
{
|
||||
vector<Size> res;
|
||||
for (int k = 1; k <= 5; ++k)
|
||||
res.push_back(Size(640 * k, 480 * k));
|
||||
return res;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(All, Imgcodecs_ExtSize,
|
||||
testing::Combine(
|
||||
testing::ValuesIn(all_exts),
|
||||
testing::ValuesIn(all_sizes())));
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PXM
|
||||
typedef testing::TestWithParam<bool> Imgcodecs_pbm;
|
||||
TEST_P(Imgcodecs_pbm, write_read)
|
||||
{
|
||||
bool binary = GetParam();
|
||||
const String ext = "pbm";
|
||||
const string full_name = cv::tempfile(ext.c_str());
|
||||
|
||||
Size size(640, 480);
|
||||
const Point2i center = Point2i(size.width / 2, size.height / 2);
|
||||
const int radius = std::min(size.height, size.width / 4);
|
||||
Mat image(size, CV_8UC1, Scalar::all(0));
|
||||
circle(image, center, radius, Scalar::all(255));
|
||||
|
||||
vector<int> pbm_params;
|
||||
pbm_params.push_back(IMWRITE_PXM_BINARY);
|
||||
pbm_params.push_back(binary);
|
||||
|
||||
imwrite( full_name, image, pbm_params );
|
||||
Mat loaded = imread(full_name, IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(loaded.empty());
|
||||
|
||||
EXPECT_EQ(0, cvtest::norm(loaded, image, NORM_INF));
|
||||
|
||||
FILE *f = fopen(full_name.c_str(), "rb");
|
||||
ASSERT_TRUE(f != NULL);
|
||||
ASSERT_EQ('P', getc(f));
|
||||
ASSERT_EQ('1' + (binary ? 3 : 0), getc(f));
|
||||
fclose(f);
|
||||
EXPECT_EQ(0, remove(full_name.c_str()));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(All, Imgcodecs_pbm, testing::Bool());
|
||||
#endif
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
TEST(Imgcodecs_Bmp, read_rle8)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
Mat rle = imread(root + "readwrite/rle8.bmp");
|
||||
ASSERT_FALSE(rle.empty());
|
||||
Mat ord = imread(root + "readwrite/ordinary.bmp");
|
||||
ASSERT_FALSE(ord.empty());
|
||||
EXPECT_LE(cvtest::norm(rle, ord, NORM_L2), 1.e-10);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), rle, ord);
|
||||
}
|
||||
|
||||
#ifdef HAVE_IMGCODEC_HDR
|
||||
TEST(Imgcodecs_Hdr, regression)
|
||||
{
|
||||
string folder = string(cvtest::TS::ptr()->get_data_path()) + "/readwrite/";
|
||||
string name_rle = folder + "rle.hdr";
|
||||
string name_no_rle = folder + "no_rle.hdr";
|
||||
Mat img_rle = imread(name_rle, -1);
|
||||
ASSERT_FALSE(img_rle.empty()) << "Could not open " << name_rle;
|
||||
Mat img_no_rle = imread(name_no_rle, -1);
|
||||
ASSERT_FALSE(img_no_rle.empty()) << "Could not open " << name_no_rle;
|
||||
|
||||
double min = 0.0, max = 1.0;
|
||||
minMaxLoc(abs(img_rle - img_no_rle), &min, &max);
|
||||
ASSERT_FALSE(max > DBL_EPSILON);
|
||||
string tmp_file_name = tempfile(".hdr");
|
||||
vector<int>param(1);
|
||||
for(int i = 0; i < 2; i++) {
|
||||
param[0] = i;
|
||||
imwrite(tmp_file_name, img_rle, param);
|
||||
Mat written_img = imread(tmp_file_name, -1);
|
||||
ASSERT_FALSE(written_img.empty()) << "Could not open " << tmp_file_name;
|
||||
minMaxLoc(abs(img_rle - written_img), &min, &max);
|
||||
ASSERT_FALSE(max > DBL_EPSILON);
|
||||
}
|
||||
remove(tmp_file_name.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PXM
|
||||
TEST(Imgcodecs_Pam, read_write)
|
||||
{
|
||||
string folder = string(cvtest::TS::ptr()->get_data_path()) + "readwrite/";
|
||||
string filepath = folder + "lena.pam";
|
||||
|
||||
cv::Mat img = cv::imread(filepath);
|
||||
ASSERT_FALSE(img.empty());
|
||||
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_PAM_TUPLETYPE);
|
||||
params.push_back(IMWRITE_PAM_FORMAT_RGB);
|
||||
|
||||
string writefile = cv::tempfile(".pam");
|
||||
EXPECT_NO_THROW(cv::imwrite(writefile, img, params));
|
||||
cv::Mat reread = cv::imread(writefile);
|
||||
|
||||
string writefile_no_param = cv::tempfile(".pam");
|
||||
EXPECT_NO_THROW(cv::imwrite(writefile_no_param, img));
|
||||
cv::Mat reread_no_param = cv::imread(writefile_no_param);
|
||||
|
||||
EXPECT_EQ(0, cvtest::norm(reread, reread_no_param, NORM_INF));
|
||||
EXPECT_EQ(0, cvtest::norm(img, reread, NORM_INF));
|
||||
|
||||
remove(writefile.c_str());
|
||||
remove(writefile_no_param.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PFM
|
||||
TEST(Imgcodecs_Pfm, read_write)
|
||||
{
|
||||
Mat img = imread(findDataFile("readwrite/lena.pam"));
|
||||
ASSERT_FALSE(img.empty());
|
||||
img.convertTo(img, CV_32F, 1/255.0f);
|
||||
|
||||
std::vector<int> params;
|
||||
string writefile = cv::tempfile(".pfm");
|
||||
EXPECT_NO_THROW(cv::imwrite(writefile, img, params));
|
||||
cv::Mat reread = cv::imread(writefile, IMREAD_UNCHANGED);
|
||||
|
||||
string writefile_no_param = cv::tempfile(".pfm");
|
||||
EXPECT_NO_THROW(cv::imwrite(writefile_no_param, img));
|
||||
cv::Mat reread_no_param = cv::imread(writefile_no_param, IMREAD_UNCHANGED);
|
||||
|
||||
EXPECT_EQ(0, cvtest::norm(reread, reread_no_param, NORM_INF));
|
||||
EXPECT_EQ(0, cvtest::norm(img, reread, NORM_INF));
|
||||
|
||||
EXPECT_EQ(0, remove(writefile.c_str()));
|
||||
EXPECT_EQ(0, remove(writefile_no_param.c_str()));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(Imgcodecs, write_parameter_type)
|
||||
{
|
||||
cv::Mat m(10, 10, CV_8UC1, cv::Scalar::all(0));
|
||||
cv::Mat1b m_type = cv::Mat1b::zeros(10, 10);
|
||||
string tmp_file = cv::tempfile(".bmp");
|
||||
EXPECT_NO_THROW(cv::imwrite(tmp_file, cv::Mat(m * 2))) << "* Failed with cv::Mat";
|
||||
EXPECT_NO_THROW(cv::imwrite(tmp_file, m * 2)) << "* Failed with cv::MatExpr";
|
||||
EXPECT_NO_THROW(cv::imwrite(tmp_file, m_type)) << "* Failed with cv::Mat_";
|
||||
EXPECT_NO_THROW(cv::imwrite(tmp_file, m_type * 2)) << "* Failed with cv::MatExpr(Mat_)";
|
||||
cv::Matx<uchar, 10, 10> matx;
|
||||
EXPECT_NO_THROW(cv::imwrite(tmp_file, matx)) << "* Failed with cv::Matx";
|
||||
EXPECT_EQ(0, remove(tmp_file.c_str()));
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
#ifdef HAVE_OPENEXR
|
||||
#include "test_exr.impl.hpp"
|
||||
#endif
|
||||
183
modules/imgcodecs/test/test_jpeg.cpp
Normal file
183
modules/imgcodecs/test/test_jpeg.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
|
||||
/**
|
||||
* Test for check whether reading exif orientation tag was processed successfully or not
|
||||
* The test info is the set of 8 images named testExifRotate_{1 to 8}.jpg
|
||||
* The test image is the square 10x10 points divided by four sub-squares:
|
||||
* (R corresponds to Red, G to Green, B to Blue, W to white)
|
||||
* --------- ---------
|
||||
* | R | G | | G | R |
|
||||
* |-------| - (tag 1) |-------| - (tag 2)
|
||||
* | B | W | | W | B |
|
||||
* --------- ---------
|
||||
*
|
||||
* --------- ---------
|
||||
* | W | B | | B | W |
|
||||
* |-------| - (tag 3) |-------| - (tag 4)
|
||||
* | G | R | | R | G |
|
||||
* --------- ---------
|
||||
*
|
||||
* --------- ---------
|
||||
* | R | B | | G | W |
|
||||
* |-------| - (tag 5) |-------| - (tag 6)
|
||||
* | G | W | | R | B |
|
||||
* --------- ---------
|
||||
*
|
||||
* --------- ---------
|
||||
* | W | G | | B | R |
|
||||
* |-------| - (tag 7) |-------| - (tag 8)
|
||||
* | B | R | | W | G |
|
||||
* --------- ---------
|
||||
*
|
||||
*
|
||||
* Every image contains exif field with orientation tag (0x112)
|
||||
* After reading each image the corresponding matrix must be read as
|
||||
* ---------
|
||||
* | R | G |
|
||||
* |-------|
|
||||
* | B | W |
|
||||
* ---------
|
||||
*
|
||||
*/
|
||||
|
||||
typedef testing::TestWithParam<string> Imgcodecs_Jpeg_Exif;
|
||||
|
||||
TEST_P(Imgcodecs_Jpeg_Exif, exif_orientation)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + GetParam();
|
||||
const int colorThresholdHigh = 250;
|
||||
const int colorThresholdLow = 5;
|
||||
|
||||
Mat m_img = imread(filename);
|
||||
ASSERT_FALSE(m_img.empty());
|
||||
Vec3b vec;
|
||||
|
||||
//Checking the first quadrant (with supposed red)
|
||||
vec = m_img.at<Vec3b>(2, 2); //some point inside the square
|
||||
EXPECT_LE(vec.val[0], colorThresholdLow);
|
||||
EXPECT_LE(vec.val[1], colorThresholdLow);
|
||||
EXPECT_GE(vec.val[2], colorThresholdHigh);
|
||||
|
||||
//Checking the second quadrant (with supposed green)
|
||||
vec = m_img.at<Vec3b>(2, 7); //some point inside the square
|
||||
EXPECT_LE(vec.val[0], colorThresholdLow);
|
||||
EXPECT_GE(vec.val[1], colorThresholdHigh);
|
||||
EXPECT_LE(vec.val[2], colorThresholdLow);
|
||||
|
||||
//Checking the third quadrant (with supposed blue)
|
||||
vec = m_img.at<Vec3b>(7, 2); //some point inside the square
|
||||
EXPECT_GE(vec.val[0], colorThresholdHigh);
|
||||
EXPECT_LE(vec.val[1], colorThresholdLow);
|
||||
EXPECT_LE(vec.val[2], colorThresholdLow);
|
||||
}
|
||||
|
||||
const string exif_files[] =
|
||||
{
|
||||
"readwrite/testExifOrientation_1.jpg",
|
||||
"readwrite/testExifOrientation_2.jpg",
|
||||
"readwrite/testExifOrientation_3.jpg",
|
||||
"readwrite/testExifOrientation_4.jpg",
|
||||
"readwrite/testExifOrientation_5.jpg",
|
||||
"readwrite/testExifOrientation_6.jpg",
|
||||
"readwrite/testExifOrientation_7.jpg",
|
||||
"readwrite/testExifOrientation_8.jpg"
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ExifFiles, Imgcodecs_Jpeg_Exif,
|
||||
testing::ValuesIn(exif_files));
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
TEST(Imgcodecs_Jpeg, encode_empty)
|
||||
{
|
||||
cv::Mat img;
|
||||
std::vector<uchar> jpegImg;
|
||||
ASSERT_THROW(cv::imencode(".jpg", img, jpegImg), cv::Exception);
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Jpeg, encode_decode_progressive_jpeg)
|
||||
{
|
||||
cvtest::TS& ts = *cvtest::TS::ptr();
|
||||
string input = string(ts.get_data_path()) + "../cv/shared/lena.png";
|
||||
cv::Mat img = cv::imread(input);
|
||||
ASSERT_FALSE(img.empty());
|
||||
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_JPEG_PROGRESSIVE);
|
||||
params.push_back(1);
|
||||
|
||||
string output_progressive = cv::tempfile(".jpg");
|
||||
EXPECT_NO_THROW(cv::imwrite(output_progressive, img, params));
|
||||
cv::Mat img_jpg_progressive = cv::imread(output_progressive);
|
||||
|
||||
string output_normal = cv::tempfile(".jpg");
|
||||
EXPECT_NO_THROW(cv::imwrite(output_normal, img));
|
||||
cv::Mat img_jpg_normal = cv::imread(output_normal);
|
||||
|
||||
EXPECT_EQ(0, cvtest::norm(img_jpg_progressive, img_jpg_normal, NORM_INF));
|
||||
|
||||
EXPECT_EQ(0, remove(output_progressive.c_str()));
|
||||
EXPECT_EQ(0, remove(output_normal.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Jpeg, encode_decode_optimize_jpeg)
|
||||
{
|
||||
cvtest::TS& ts = *cvtest::TS::ptr();
|
||||
string input = string(ts.get_data_path()) + "../cv/shared/lena.png";
|
||||
cv::Mat img = cv::imread(input);
|
||||
ASSERT_FALSE(img.empty());
|
||||
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_JPEG_OPTIMIZE);
|
||||
params.push_back(1);
|
||||
|
||||
string output_optimized = cv::tempfile(".jpg");
|
||||
EXPECT_NO_THROW(cv::imwrite(output_optimized, img, params));
|
||||
cv::Mat img_jpg_optimized = cv::imread(output_optimized);
|
||||
|
||||
string output_normal = cv::tempfile(".jpg");
|
||||
EXPECT_NO_THROW(cv::imwrite(output_normal, img));
|
||||
cv::Mat img_jpg_normal = cv::imread(output_normal);
|
||||
|
||||
EXPECT_EQ(0, cvtest::norm(img_jpg_optimized, img_jpg_normal, NORM_INF));
|
||||
|
||||
EXPECT_EQ(0, remove(output_optimized.c_str()));
|
||||
EXPECT_EQ(0, remove(output_normal.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Jpeg, encode_decode_rst_jpeg)
|
||||
{
|
||||
cvtest::TS& ts = *cvtest::TS::ptr();
|
||||
string input = string(ts.get_data_path()) + "../cv/shared/lena.png";
|
||||
cv::Mat img = cv::imread(input);
|
||||
ASSERT_FALSE(img.empty());
|
||||
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_JPEG_RST_INTERVAL);
|
||||
params.push_back(1);
|
||||
|
||||
string output_rst = cv::tempfile(".jpg");
|
||||
EXPECT_NO_THROW(cv::imwrite(output_rst, img, params));
|
||||
cv::Mat img_jpg_rst = cv::imread(output_rst);
|
||||
|
||||
string output_normal = cv::tempfile(".jpg");
|
||||
EXPECT_NO_THROW(cv::imwrite(output_normal, img));
|
||||
cv::Mat img_jpg_normal = cv::imread(output_normal);
|
||||
|
||||
EXPECT_EQ(0, cvtest::norm(img_jpg_rst, img_jpg_normal, NORM_INF));
|
||||
|
||||
EXPECT_EQ(0, remove(output_rst.c_str()));
|
||||
EXPECT_EQ(0, remove(output_normal.c_str()));
|
||||
}
|
||||
|
||||
#endif // HAVE_JPEG
|
||||
|
||||
}} // namespace
|
||||
10
modules/imgcodecs/test/test_main.cpp
Normal file
10
modules/imgcodecs/test/test_main.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
#if defined(HAVE_HPX)
|
||||
#include <hpx/hpx_main.hpp>
|
||||
#endif
|
||||
|
||||
CV_TEST_MAIN("highgui")
|
||||
191
modules/imgcodecs/test/test_png.cpp
Normal file
191
modules/imgcodecs/test/test_png.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
|
||||
TEST(Imgcodecs_Png, write_big)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "readwrite/read.png";
|
||||
const string dst_file = cv::tempfile(".png");
|
||||
Mat img;
|
||||
ASSERT_NO_THROW(img = imread(filename));
|
||||
ASSERT_FALSE(img.empty());
|
||||
EXPECT_EQ(13043, img.cols);
|
||||
EXPECT_EQ(13917, img.rows);
|
||||
ASSERT_NO_THROW(imwrite(dst_file, img));
|
||||
EXPECT_EQ(0, remove(dst_file.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Png, encode)
|
||||
{
|
||||
vector<uchar> buff;
|
||||
Mat img_gt = Mat::zeros(1000, 1000, CV_8U);
|
||||
vector<int> param;
|
||||
param.push_back(IMWRITE_PNG_COMPRESSION);
|
||||
param.push_back(3); //default(3) 0-9.
|
||||
EXPECT_NO_THROW(imencode(".png", img_gt, buff, param));
|
||||
Mat img;
|
||||
EXPECT_NO_THROW(img = imdecode(buff, IMREAD_ANYDEPTH)); // hang
|
||||
EXPECT_FALSE(img.empty());
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, img_gt);
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Png, regression_ImreadVSCvtColor)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string imgName = root + "../cv/shared/lena.png";
|
||||
Mat original_image = imread(imgName);
|
||||
Mat gray_by_codec = imread(imgName, IMREAD_GRAYSCALE);
|
||||
Mat gray_by_cvt;
|
||||
cvtColor(original_image, gray_by_cvt, COLOR_BGR2GRAY);
|
||||
|
||||
Mat diff;
|
||||
absdiff(gray_by_codec, gray_by_cvt, diff);
|
||||
EXPECT_LT(cvtest::mean(diff)[0], 1.);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(10, 0), gray_by_codec, gray_by_cvt);
|
||||
}
|
||||
|
||||
// Test OpenCV issue 3075 is solved
|
||||
TEST(Imgcodecs_Png, read_color_palette_with_alpha)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
Mat img;
|
||||
|
||||
// First Test : Read PNG with alpha, imread flag -1
|
||||
img = imread(root + "readwrite/color_palette_alpha.png", IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 4);
|
||||
|
||||
// pixel is red in BGRA
|
||||
EXPECT_EQ(img.at<Vec4b>(0, 0), Vec4b(0, 0, 255, 255));
|
||||
EXPECT_EQ(img.at<Vec4b>(0, 1), Vec4b(0, 0, 255, 255));
|
||||
|
||||
// Second Test : Read PNG without alpha, imread flag -1
|
||||
img = imread(root + "readwrite/color_palette_no_alpha.png", IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
|
||||
// pixel is red in BGR
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
|
||||
|
||||
// Third Test : Read PNG with alpha, imread flag 1
|
||||
img = imread(root + "readwrite/color_palette_alpha.png", IMREAD_COLOR);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
|
||||
// pixel is red in BGR
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
|
||||
|
||||
// Fourth Test : Read PNG without alpha, imread flag 1
|
||||
img = imread(root + "readwrite/color_palette_no_alpha.png", IMREAD_COLOR);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
|
||||
// pixel is red in BGR
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for check whether reading exif orientation tag was processed successfully or not
|
||||
* The test info is the set of 8 images named testExifRotate_{1 to 8}.png
|
||||
* The test image is the square 10x10 points divided by four sub-squares:
|
||||
* (R corresponds to Red, G to Green, B to Blue, W to white)
|
||||
* --------- ---------
|
||||
* | R | G | | G | R |
|
||||
* |-------| - (tag 1) |-------| - (tag 2)
|
||||
* | B | W | | W | B |
|
||||
* --------- ---------
|
||||
*
|
||||
* --------- ---------
|
||||
* | W | B | | B | W |
|
||||
* |-------| - (tag 3) |-------| - (tag 4)
|
||||
* | G | R | | R | G |
|
||||
* --------- ---------
|
||||
*
|
||||
* --------- ---------
|
||||
* | R | B | | G | W |
|
||||
* |-------| - (tag 5) |-------| - (tag 6)
|
||||
* | G | W | | R | B |
|
||||
* --------- ---------
|
||||
*
|
||||
* --------- ---------
|
||||
* | W | G | | B | R |
|
||||
* |-------| - (tag 7) |-------| - (tag 8)
|
||||
* | B | R | | W | G |
|
||||
* --------- ---------
|
||||
*
|
||||
*
|
||||
* Every image contains exif field with orientation tag (0x112)
|
||||
* After reading each image and applying the orientation tag,
|
||||
* the resulting image should be:
|
||||
* ---------
|
||||
* | R | G |
|
||||
* |-------|
|
||||
* | B | W |
|
||||
* ---------
|
||||
*
|
||||
*/
|
||||
|
||||
typedef testing::TestWithParam<string> Imgcodecs_PNG_Exif;
|
||||
|
||||
// Solution to issue 16579: PNG read doesn't support Exif orientation data
|
||||
#ifdef OPENCV_IMGCODECS_PNG_WITH_EXIF
|
||||
TEST_P(Imgcodecs_PNG_Exif, exif_orientation)
|
||||
#else
|
||||
TEST_P(Imgcodecs_PNG_Exif, DISABLED_exif_orientation)
|
||||
#endif
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + GetParam();
|
||||
const int colorThresholdHigh = 250;
|
||||
const int colorThresholdLow = 5;
|
||||
|
||||
Mat m_img = imread(filename);
|
||||
ASSERT_FALSE(m_img.empty());
|
||||
Vec3b vec;
|
||||
|
||||
//Checking the first quadrant (with supposed red)
|
||||
vec = m_img.at<Vec3b>(2, 2); //some point inside the square
|
||||
EXPECT_LE(vec.val[0], colorThresholdLow);
|
||||
EXPECT_LE(vec.val[1], colorThresholdLow);
|
||||
EXPECT_GE(vec.val[2], colorThresholdHigh);
|
||||
|
||||
//Checking the second quadrant (with supposed green)
|
||||
vec = m_img.at<Vec3b>(2, 7); //some point inside the square
|
||||
EXPECT_LE(vec.val[0], colorThresholdLow);
|
||||
EXPECT_GE(vec.val[1], colorThresholdHigh);
|
||||
EXPECT_LE(vec.val[2], colorThresholdLow);
|
||||
|
||||
//Checking the third quadrant (with supposed blue)
|
||||
vec = m_img.at<Vec3b>(7, 2); //some point inside the square
|
||||
EXPECT_GE(vec.val[0], colorThresholdHigh);
|
||||
EXPECT_LE(vec.val[1], colorThresholdLow);
|
||||
EXPECT_LE(vec.val[2], colorThresholdLow);
|
||||
}
|
||||
|
||||
const string exif_files[] =
|
||||
{
|
||||
"readwrite/testExifOrientation_1.png",
|
||||
"readwrite/testExifOrientation_2.png",
|
||||
"readwrite/testExifOrientation_3.png",
|
||||
"readwrite/testExifOrientation_4.png",
|
||||
"readwrite/testExifOrientation_5.png",
|
||||
"readwrite/testExifOrientation_6.png",
|
||||
"readwrite/testExifOrientation_7.png",
|
||||
"readwrite/testExifOrientation_8.png"
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ExifFiles, Imgcodecs_PNG_Exif,
|
||||
testing::ValuesIn(exif_files));
|
||||
|
||||
#endif // HAVE_PNG
|
||||
|
||||
}} // namespace
|
||||
75
modules/imgcodecs/test/test_precomp.hpp
Normal file
75
modules/imgcodecs/test/test_precomp.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#ifndef __OPENCV_TEST_PRECOMP_HPP__
|
||||
#define __OPENCV_TEST_PRECOMP_HPP__
|
||||
|
||||
#include "opencv2/ts.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/imgproc/imgproc_c.h"
|
||||
|
||||
namespace cv {
|
||||
|
||||
static inline
|
||||
void PrintTo(const ImreadModes& val, std::ostream* os)
|
||||
{
|
||||
int v = val;
|
||||
if (v == IMREAD_UNCHANGED && (v & IMREAD_IGNORE_ORIENTATION) != 0)
|
||||
{
|
||||
CV_Assert(IMREAD_UNCHANGED == -1);
|
||||
*os << "IMREAD_UNCHANGED";
|
||||
return;
|
||||
}
|
||||
if ((v & IMREAD_COLOR) != 0)
|
||||
{
|
||||
CV_Assert(IMREAD_COLOR == 1);
|
||||
v &= ~IMREAD_COLOR;
|
||||
*os << "IMREAD_COLOR" << (v == 0 ? "" : " | ");
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Assert(IMREAD_GRAYSCALE == 0);
|
||||
*os << "IMREAD_GRAYSCALE" << (v == 0 ? "" : " | ");
|
||||
}
|
||||
if ((v & IMREAD_ANYDEPTH) != 0)
|
||||
{
|
||||
v &= ~IMREAD_ANYDEPTH;
|
||||
*os << "IMREAD_ANYDEPTH" << (v == 0 ? "" : " | ");
|
||||
}
|
||||
if ((v & IMREAD_ANYCOLOR) != 0)
|
||||
{
|
||||
v &= ~IMREAD_ANYCOLOR;
|
||||
*os << "IMREAD_ANYCOLOR" << (v == 0 ? "" : " | ");
|
||||
}
|
||||
if ((v & IMREAD_LOAD_GDAL) != 0)
|
||||
{
|
||||
v &= ~IMREAD_LOAD_GDAL;
|
||||
*os << "IMREAD_LOAD_GDAL" << (v == 0 ? "" : " | ");
|
||||
}
|
||||
if ((v & IMREAD_IGNORE_ORIENTATION) != 0)
|
||||
{
|
||||
v &= ~IMREAD_IGNORE_ORIENTATION;
|
||||
*os << "IMREAD_IGNORE_ORIENTATION" << (v == 0 ? "" : " | ");
|
||||
}
|
||||
switch (v)
|
||||
{
|
||||
case IMREAD_UNCHANGED: return;
|
||||
case IMREAD_GRAYSCALE: return;
|
||||
case IMREAD_COLOR: return;
|
||||
case IMREAD_ANYDEPTH: return;
|
||||
case IMREAD_ANYCOLOR: return;
|
||||
case IMREAD_LOAD_GDAL: return;
|
||||
case IMREAD_REDUCED_GRAYSCALE_2: // fallthru
|
||||
case IMREAD_REDUCED_COLOR_2: *os << "REDUCED_2"; return;
|
||||
case IMREAD_REDUCED_GRAYSCALE_4: // fallthru
|
||||
case IMREAD_REDUCED_COLOR_4: *os << "REDUCED_4"; return;
|
||||
case IMREAD_REDUCED_GRAYSCALE_8: // fallthru
|
||||
case IMREAD_REDUCED_COLOR_8: *os << "REDUCED_8"; return;
|
||||
case IMREAD_IGNORE_ORIENTATION: return;
|
||||
} // don't use "default:" to emit compiler warnings
|
||||
*os << "IMREAD_UNKNOWN(" << (int)v << ")";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
306
modules/imgcodecs/test/test_read_write.cpp
Normal file
306
modules/imgcodecs/test/test_read_write.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
#include "test_common.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
/* < <file_name, image_size>, <imread mode, scale> > */
|
||||
typedef tuple< tuple<string, Size>, tuple<ImreadModes, int> > Imgcodecs_Resize_t;
|
||||
|
||||
typedef testing::TestWithParam< Imgcodecs_Resize_t > Imgcodecs_Resize;
|
||||
|
||||
/* resize_flag_and_dims = <imread_flag, scale>*/
|
||||
const tuple <ImreadModes, int> resize_flag_and_dims[] =
|
||||
{
|
||||
make_tuple(IMREAD_UNCHANGED, 1),
|
||||
make_tuple(IMREAD_REDUCED_GRAYSCALE_2, 2),
|
||||
make_tuple(IMREAD_REDUCED_GRAYSCALE_4, 4),
|
||||
make_tuple(IMREAD_REDUCED_GRAYSCALE_8, 8),
|
||||
make_tuple(IMREAD_REDUCED_COLOR_2, 2),
|
||||
make_tuple(IMREAD_REDUCED_COLOR_4, 4),
|
||||
make_tuple(IMREAD_REDUCED_COLOR_8, 8)
|
||||
};
|
||||
|
||||
const tuple<string, Size> images[] =
|
||||
{
|
||||
#ifdef HAVE_JPEG
|
||||
make_tuple<string, Size>("../cv/imgproc/stuff.jpg", Size(640, 480)),
|
||||
#endif
|
||||
#ifdef HAVE_PNG
|
||||
make_tuple<string, Size>("../cv/shared/pic1.png", Size(400, 300)),
|
||||
#endif
|
||||
make_tuple<string, Size>("../highgui/readwrite/ordinary.bmp", Size(480, 272)),
|
||||
};
|
||||
|
||||
TEST_P(Imgcodecs_Resize, imread_reduce_flags)
|
||||
{
|
||||
const string file_name = findDataFile(get<0>(get<0>(GetParam())));
|
||||
const Size imageSize = get<1>(get<0>(GetParam()));
|
||||
|
||||
const int imread_flag = get<0>(get<1>(GetParam()));
|
||||
const int scale = get<1>(get<1>(GetParam()));
|
||||
|
||||
const int cols = imageSize.width / scale;
|
||||
const int rows = imageSize.height / scale;
|
||||
{
|
||||
Mat img = imread(file_name, imread_flag);
|
||||
ASSERT_FALSE(img.empty());
|
||||
EXPECT_EQ(cols, img.cols);
|
||||
EXPECT_EQ(rows, img.rows);
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
TEST_P(Imgcodecs_Resize, imdecode_reduce_flags)
|
||||
{
|
||||
const string file_name = findDataFile(get<0>(get<0>(GetParam())));
|
||||
const Size imageSize = get<1>(get<0>(GetParam()));
|
||||
|
||||
const int imread_flag = get<0>(get<1>(GetParam()));
|
||||
const int scale = get<1>(get<1>(GetParam()));
|
||||
|
||||
const int cols = imageSize.width / scale;
|
||||
const int rows = imageSize.height / scale;
|
||||
|
||||
const std::ios::openmode mode = std::ios::in | std::ios::binary;
|
||||
std::ifstream ifs(file_name.c_str(), mode);
|
||||
ASSERT_TRUE(ifs.is_open());
|
||||
|
||||
ifs.seekg(0, std::ios::end);
|
||||
const size_t sz = static_cast<size_t>(ifs.tellg());
|
||||
ifs.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<char> content(sz);
|
||||
ifs.read((char*)content.data(), sz);
|
||||
ASSERT_FALSE(ifs.fail());
|
||||
|
||||
{
|
||||
Mat img = imdecode(Mat(content), imread_flag);
|
||||
ASSERT_FALSE(img.empty());
|
||||
EXPECT_EQ(cols, img.cols);
|
||||
EXPECT_EQ(rows, img.rows);
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Resize,
|
||||
testing::Combine(
|
||||
testing::ValuesIn(images),
|
||||
testing::ValuesIn(resize_flag_and_dims)
|
||||
)
|
||||
);
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
TEST(Imgcodecs_Image, read_write_bmp)
|
||||
{
|
||||
const size_t IMAGE_COUNT = 10;
|
||||
const double thresDbell = 32;
|
||||
|
||||
for (size_t i = 0; i < IMAGE_COUNT; ++i)
|
||||
{
|
||||
stringstream s; s << i;
|
||||
const string digit = s.str();
|
||||
const string src_name = TS::ptr()->get_data_path() + "../python/images/QCIF_0" + digit + ".bmp";
|
||||
const string dst_name = cv::tempfile((digit + ".bmp").c_str());
|
||||
Mat image = imread(src_name);
|
||||
ASSERT_FALSE(image.empty());
|
||||
|
||||
resize(image, image, Size(968, 757), 0.0, 0.0, INTER_CUBIC);
|
||||
imwrite(dst_name, image);
|
||||
Mat loaded = imread(dst_name);
|
||||
ASSERT_FALSE(loaded.empty());
|
||||
|
||||
double psnr = cvtest::PSNR(loaded, image);
|
||||
EXPECT_GT(psnr, thresDbell);
|
||||
|
||||
vector<uchar> from_file;
|
||||
|
||||
FILE *f = fopen(dst_name.c_str(), "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long len = ftell(f);
|
||||
from_file.resize((size_t)len);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
from_file.resize(fread(&from_file[0], 1, from_file.size(), f));
|
||||
fclose(f);
|
||||
|
||||
vector<uchar> buf;
|
||||
imencode(".bmp", image, buf);
|
||||
ASSERT_EQ(buf, from_file);
|
||||
|
||||
Mat buf_loaded = imdecode(Mat(buf), 1);
|
||||
ASSERT_FALSE(buf_loaded.empty());
|
||||
|
||||
psnr = cvtest::PSNR(buf_loaded, image);
|
||||
EXPECT_GT(psnr, thresDbell);
|
||||
|
||||
EXPECT_EQ(0, remove(dst_name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
typedef string Ext;
|
||||
typedef testing::TestWithParam<Ext> Imgcodecs_Image;
|
||||
|
||||
const string exts[] = {
|
||||
#ifdef HAVE_PNG
|
||||
"png",
|
||||
#endif
|
||||
#ifdef HAVE_TIFF
|
||||
"tiff",
|
||||
#endif
|
||||
#ifdef HAVE_JPEG
|
||||
"jpg",
|
||||
#endif
|
||||
#if (defined(HAVE_JASPER) && defined(OPENCV_IMGCODECS_ENABLE_JASPER_TESTS)) \
|
||||
|| defined(HAVE_OPENJPEG)
|
||||
"jp2",
|
||||
#endif
|
||||
#if 0 /*defined HAVE_OPENEXR && !defined __APPLE__*/
|
||||
"exr",
|
||||
#endif
|
||||
"bmp",
|
||||
#ifdef HAVE_IMGCODEC_PXM
|
||||
"ppm",
|
||||
#endif
|
||||
#ifdef HAVE_IMGCODEC_SUNRASTER
|
||||
"ras",
|
||||
#endif
|
||||
};
|
||||
|
||||
static
|
||||
void test_image_io(const Mat& image, const std::string& fname, const std::string& ext, int imreadFlag, double psnrThreshold)
|
||||
{
|
||||
vector<uchar> buf;
|
||||
ASSERT_NO_THROW(imencode("." + ext, image, buf));
|
||||
|
||||
ASSERT_NO_THROW(imwrite(fname, image));
|
||||
|
||||
FILE *f = fopen(fname.c_str(), "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long len = ftell(f);
|
||||
cout << "File size: " << len << " bytes" << endl;
|
||||
EXPECT_GT(len, 1024) << "File is small. Test or implementation is broken";
|
||||
fseek(f, 0, SEEK_SET);
|
||||
vector<uchar> file_buf((size_t)len);
|
||||
EXPECT_EQ(len, (long)fread(&file_buf[0], 1, (size_t)len, f));
|
||||
fclose(f); f = NULL;
|
||||
|
||||
EXPECT_EQ(buf, file_buf) << "imwrite() / imencode() calls must provide the same output (bit-exact)";
|
||||
|
||||
Mat buf_loaded = imdecode(Mat(buf), imreadFlag);
|
||||
EXPECT_FALSE(buf_loaded.empty());
|
||||
|
||||
Mat loaded = imread(fname, imreadFlag);
|
||||
EXPECT_FALSE(loaded.empty());
|
||||
|
||||
EXPECT_EQ(0, cv::norm(loaded, buf_loaded, NORM_INF)) << "imread() and imdecode() calls must provide the same result (bit-exact)";
|
||||
|
||||
double psnr = cvtest::PSNR(loaded, image);
|
||||
EXPECT_GT(psnr, psnrThreshold);
|
||||
|
||||
// not necessary due bitexact check above
|
||||
//double buf_psnr = cvtest::PSNR(buf_loaded, image);
|
||||
//EXPECT_GT(buf_psnr, psnrThreshold);
|
||||
|
||||
#if 0 // debug
|
||||
if (psnr <= psnrThreshold /*|| buf_psnr <= thresDbell*/)
|
||||
{
|
||||
cout << "File: " << fname << endl;
|
||||
imshow("origin", image);
|
||||
imshow("imread", loaded);
|
||||
imshow("imdecode", buf_loaded);
|
||||
waitKey();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_P(Imgcodecs_Image, read_write_BGR)
|
||||
{
|
||||
const string ext = this->GetParam();
|
||||
const string fname = cv::tempfile(ext.c_str());
|
||||
|
||||
double psnrThreshold = 100;
|
||||
if (ext == "jpg")
|
||||
psnrThreshold = 32;
|
||||
#if defined(HAVE_JASPER)
|
||||
if (ext == "jp2")
|
||||
psnrThreshold = 95;
|
||||
#elif defined(HAVE_OPENJPEG)
|
||||
if (ext == "jp2")
|
||||
psnrThreshold = 35;
|
||||
#endif
|
||||
|
||||
Mat image = generateTestImageBGR();
|
||||
EXPECT_NO_THROW(test_image_io(image, fname, ext, IMREAD_COLOR, psnrThreshold));
|
||||
|
||||
EXPECT_EQ(0, remove(fname.c_str()));
|
||||
}
|
||||
|
||||
TEST_P(Imgcodecs_Image, read_write_GRAYSCALE)
|
||||
{
|
||||
const string ext = this->GetParam();
|
||||
|
||||
if (false
|
||||
|| ext == "ppm" // grayscale is not implemented
|
||||
|| ext == "ras" // broken (black result)
|
||||
)
|
||||
throw SkipTestException("GRAYSCALE mode is not supported");
|
||||
|
||||
const string fname = cv::tempfile(ext.c_str());
|
||||
|
||||
double psnrThreshold = 100;
|
||||
if (ext == "jpg")
|
||||
psnrThreshold = 40;
|
||||
#if defined(HAVE_JASPER)
|
||||
if (ext == "jp2")
|
||||
psnrThreshold = 70;
|
||||
#elif defined(HAVE_OPENJPEG)
|
||||
if (ext == "jp2")
|
||||
psnrThreshold = 35;
|
||||
#endif
|
||||
|
||||
Mat image = generateTestImageGrayscale();
|
||||
EXPECT_NO_THROW(test_image_io(image, fname, ext, IMREAD_GRAYSCALE, psnrThreshold));
|
||||
|
||||
EXPECT_EQ(0, remove(fname.c_str()));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(imgcodecs, Imgcodecs_Image, testing::ValuesIn(exts));
|
||||
|
||||
TEST(Imgcodecs_Image, regression_9376)
|
||||
{
|
||||
String path = findDataFile("readwrite/regression_9376.bmp");
|
||||
Mat m = imread(path);
|
||||
ASSERT_FALSE(m.empty());
|
||||
EXPECT_EQ(32, m.cols);
|
||||
EXPECT_EQ(32, m.rows);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
TEST(Imgcodecs_Image, write_umat)
|
||||
{
|
||||
const string src_name = TS::ptr()->get_data_path() + "../python/images/baboon.bmp";
|
||||
const string dst_name = cv::tempfile(".bmp");
|
||||
|
||||
Mat image1 = imread(src_name);
|
||||
ASSERT_FALSE(image1.empty());
|
||||
|
||||
UMat image1_umat = image1.getUMat(ACCESS_RW);
|
||||
|
||||
imwrite(dst_name, image1_umat);
|
||||
|
||||
Mat image2 = imread(dst_name);
|
||||
ASSERT_FALSE(image2.empty());
|
||||
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), image1, image2);
|
||||
EXPECT_EQ(0, remove(dst_name.c_str()));
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
363
modules/imgcodecs/test/test_tiff.cpp
Normal file
363
modules/imgcodecs/test/test_tiff.cpp
Normal file
@@ -0,0 +1,363 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
#ifdef HAVE_TIFF
|
||||
|
||||
// these defines are used to resolve conflict between tiff.h and opencv2/core/types_c.h
|
||||
#define uint64 uint64_hack_
|
||||
#define int64 int64_hack_
|
||||
#include "tiff.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// Test disabled as it uses a lot of memory.
|
||||
// It is killed with SIGKILL by out of memory killer.
|
||||
TEST(Imgcodecs_Tiff, DISABLED_decode_tile16384x16384)
|
||||
#else
|
||||
TEST(Imgcodecs_Tiff, decode_tile16384x16384)
|
||||
#endif
|
||||
{
|
||||
// see issue #2161
|
||||
cv::Mat big(16384, 16384, CV_8UC1, cv::Scalar::all(0));
|
||||
string file3 = cv::tempfile(".tiff");
|
||||
string file4 = cv::tempfile(".tiff");
|
||||
|
||||
std::vector<int> params;
|
||||
params.push_back(TIFFTAG_ROWSPERSTRIP);
|
||||
params.push_back(big.rows);
|
||||
EXPECT_NO_THROW(cv::imwrite(file4, big, params));
|
||||
EXPECT_NO_THROW(cv::imwrite(file3, big.colRange(0, big.cols - 1), params));
|
||||
big.release();
|
||||
|
||||
try
|
||||
{
|
||||
cv::imread(file3, IMREAD_UNCHANGED);
|
||||
EXPECT_NO_THROW(cv::imread(file4, IMREAD_UNCHANGED));
|
||||
}
|
||||
catch(const std::bad_alloc&)
|
||||
{
|
||||
// not enough memory
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, remove(file3.c_str()));
|
||||
EXPECT_EQ(0, remove(file4.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, write_read_16bit_big_little_endian)
|
||||
{
|
||||
// see issue #2601 "16-bit Grayscale TIFF Load Failures Due to Buffer Underflow and Endianness"
|
||||
|
||||
// Setup data for two minimal 16-bit grayscale TIFF files in both endian formats
|
||||
uchar tiff_sample_data[2][86] = { {
|
||||
// Little endian
|
||||
0x49, 0x49, 0x2a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xad, 0xde, 0xef, 0xbe, 0x06, 0x00, 0x00, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01,
|
||||
0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x01, 0x04, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x00 }, {
|
||||
// Big endian
|
||||
0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x0c, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x06, 0x01, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10,
|
||||
0x00, 0x00, 0x01, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x11,
|
||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x01, 0x17, 0x00, 0x04, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x04 }
|
||||
};
|
||||
|
||||
// Test imread() for both a little endian TIFF and big endian TIFF
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
string filename = cv::tempfile(".tiff");
|
||||
|
||||
// Write sample TIFF file
|
||||
FILE* fp = fopen(filename.c_str(), "wb");
|
||||
ASSERT_TRUE(fp != NULL);
|
||||
ASSERT_EQ((size_t)1, fwrite(tiff_sample_data[i], 86, 1, fp));
|
||||
fclose(fp);
|
||||
|
||||
Mat img = imread(filename, IMREAD_UNCHANGED);
|
||||
|
||||
EXPECT_EQ(1, img.rows);
|
||||
EXPECT_EQ(2, img.cols);
|
||||
EXPECT_EQ(CV_16U, img.type());
|
||||
EXPECT_EQ(sizeof(ushort), img.elemSize());
|
||||
EXPECT_EQ(1, img.channels());
|
||||
EXPECT_EQ(0xDEAD, img.at<ushort>(0,0));
|
||||
EXPECT_EQ(0xBEEF, img.at<ushort>(0,1));
|
||||
|
||||
EXPECT_EQ(0, remove(filename.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, decode_tile_remainder)
|
||||
{
|
||||
/* see issue #3472 - dealing with tiled images where the tile size is
|
||||
* not a multiple of image size.
|
||||
* The tiled images were created with 'convert' from ImageMagick,
|
||||
* using the command 'convert <input> -define tiff:tile-geometry=128x128 -depth [8|16] <output>
|
||||
* Note that the conversion to 16 bits expands the range from 0-255 to 0-255*255,
|
||||
* so the test converts back but rounding errors cause small differences.
|
||||
*/
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
cv::Mat img = imread(root + "readwrite/non_tiled.tif",-1);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_TRUE(img.channels() == 3);
|
||||
cv::Mat tiled8 = imread(root + "readwrite/tiled_8.tif", -1);
|
||||
ASSERT_FALSE(tiled8.empty());
|
||||
ASSERT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, tiled8);
|
||||
cv::Mat tiled16 = imread(root + "readwrite/tiled_16.tif", -1);
|
||||
ASSERT_FALSE(tiled16.empty());
|
||||
ASSERT_TRUE(tiled16.elemSize() == 6);
|
||||
tiled16.convertTo(tiled8, CV_8UC3, 1./256.);
|
||||
ASSERT_PRED_FORMAT2(cvtest::MatComparator(2, 0), img, tiled8);
|
||||
// What about 32, 64 bit?
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, decode_infinite_rowsperstrip)
|
||||
{
|
||||
const uchar sample_data[142] = {
|
||||
0x49, 0x49, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x56, 0x54,
|
||||
0x56, 0x5a, 0x59, 0x55, 0x5a, 0x00, 0x0a, 0x00, 0x00, 0x01,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00,
|
||||
0x00, 0x00, 0x02, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x03, 0x01, 0x03, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01,
|
||||
0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x15, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x16, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0x17, 0x01, 0x04, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x03, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
const string filename = cv::tempfile(".tiff");
|
||||
std::ofstream outfile(filename.c_str(), std::ofstream::binary);
|
||||
outfile.write(reinterpret_cast<const char *>(sample_data), sizeof sample_data);
|
||||
outfile.close();
|
||||
|
||||
EXPECT_NO_THROW(cv::imread(filename, IMREAD_UNCHANGED));
|
||||
|
||||
EXPECT_EQ(0, remove(filename.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, readWrite_32FC1)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test32FC1.tiff";
|
||||
const string filenameOutput = cv::tempfile(".tiff");
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC1,img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, readWrite_64FC1)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test64FC1.tiff";
|
||||
const string filenameOutput = cv::tempfile(".tiff");
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_64FC1, img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, readWrite_32FC3_SGILOG)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test32FC3_sgilog.tiff";
|
||||
const string filenameOutput = cv::tempfile(".tiff");
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC3, img.type());
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 0.01);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, readWrite_32FC3_RAW)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filenameInput = root + "readwrite/test32FC3_raw.tiff";
|
||||
const string filenameOutput = cv::tempfile(".tiff");
|
||||
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
|
||||
ASSERT_FALSE(img.empty());
|
||||
ASSERT_EQ(CV_32FC3, img.type());
|
||||
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_TIFF_COMPRESSION);
|
||||
params.push_back(1/*COMPRESSION_NONE*/);
|
||||
|
||||
ASSERT_TRUE(cv::imwrite(filenameOutput, img, params));
|
||||
const Mat img2 = cv::imread(filenameOutput, IMREAD_UNCHANGED);
|
||||
ASSERT_EQ(img2.type(), img.type());
|
||||
ASSERT_EQ(img2.size(), img.size());
|
||||
EXPECT_LE(cvtest::norm(img, img2, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
typedef testing::TestWithParam<int> Imgcodecs_Tiff_Modes;
|
||||
|
||||
TEST_P(Imgcodecs_Tiff_Modes, decode_multipage)
|
||||
{
|
||||
const int mode = GetParam();
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "readwrite/multipage.tif";
|
||||
const string page_files[] = {
|
||||
"readwrite/multipage_p1.tif",
|
||||
"readwrite/multipage_p2.tif",
|
||||
"readwrite/multipage_p3.tif",
|
||||
"readwrite/multipage_p4.tif",
|
||||
"readwrite/multipage_p5.tif",
|
||||
"readwrite/multipage_p6.tif"
|
||||
};
|
||||
const size_t page_count = sizeof(page_files)/sizeof(page_files[0]);
|
||||
vector<Mat> pages;
|
||||
bool res = imreadmulti(filename, pages, mode);
|
||||
ASSERT_TRUE(res == true);
|
||||
ASSERT_EQ(page_count, pages.size());
|
||||
for (size_t i = 0; i < page_count; i++)
|
||||
{
|
||||
const Mat page = imread(root + page_files[i], mode);
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), page, pages[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const int all_modes[] =
|
||||
{
|
||||
IMREAD_UNCHANGED,
|
||||
IMREAD_GRAYSCALE,
|
||||
IMREAD_COLOR,
|
||||
IMREAD_ANYDEPTH,
|
||||
IMREAD_ANYCOLOR
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AllModes, Imgcodecs_Tiff_Modes, testing::ValuesIn(all_modes));
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
TEST(Imgcodecs_Tiff_Modes, write_multipage)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "readwrite/multipage.tif";
|
||||
const string page_files[] = {
|
||||
"readwrite/multipage_p1.tif",
|
||||
"readwrite/multipage_p2.tif",
|
||||
"readwrite/multipage_p3.tif",
|
||||
"readwrite/multipage_p4.tif",
|
||||
"readwrite/multipage_p5.tif",
|
||||
"readwrite/multipage_p6.tif"
|
||||
};
|
||||
const size_t page_count = sizeof(page_files) / sizeof(page_files[0]);
|
||||
vector<Mat> pages;
|
||||
for (size_t i = 0; i < page_count; i++)
|
||||
{
|
||||
const Mat page = imread(root + page_files[i]);
|
||||
pages.push_back(page);
|
||||
}
|
||||
|
||||
string tmp_filename = cv::tempfile(".tiff");
|
||||
bool res = imwrite(tmp_filename, pages);
|
||||
ASSERT_TRUE(res);
|
||||
|
||||
vector<Mat> read_pages;
|
||||
imreadmulti(tmp_filename, read_pages);
|
||||
for (size_t i = 0; i < page_count; i++)
|
||||
{
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), read_pages[i], pages[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
TEST(Imgcodecs_Tiff, imdecode_no_exception_temporary_file_removed)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "../cv/shared/lena.png";
|
||||
cv::Mat img = cv::imread(filename);
|
||||
ASSERT_FALSE(img.empty());
|
||||
std::vector<uchar> buf;
|
||||
EXPECT_NO_THROW(cv::imencode(".tiff", img, buf));
|
||||
EXPECT_NO_THROW(cv::imdecode(buf, IMREAD_UNCHANGED));
|
||||
}
|
||||
|
||||
|
||||
TEST(Imgcodecs_Tiff, decode_black_and_write_image_pr12989_grayscale)
|
||||
{
|
||||
const string filename = cvtest::findDataFile("readwrite/bitsperpixel1.tiff");
|
||||
cv::Mat img;
|
||||
ASSERT_NO_THROW(img = cv::imread(filename, IMREAD_GRAYSCALE));
|
||||
ASSERT_FALSE(img.empty());
|
||||
EXPECT_EQ(64, img.cols);
|
||||
EXPECT_EQ(64, img.rows);
|
||||
EXPECT_EQ(CV_8UC1, img.type()) << cv::typeToString(img.type());
|
||||
// Check for 0/255 values only: 267 + 3829 = 64*64
|
||||
EXPECT_EQ(267, countNonZero(img == 0));
|
||||
EXPECT_EQ(3829, countNonZero(img == 255));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, decode_black_and_write_image_pr12989_default)
|
||||
{
|
||||
const string filename = cvtest::findDataFile("readwrite/bitsperpixel1.tiff");
|
||||
cv::Mat img;
|
||||
ASSERT_NO_THROW(img = cv::imread(filename)); // by default image type is CV_8UC3
|
||||
ASSERT_FALSE(img.empty());
|
||||
EXPECT_EQ(64, img.cols);
|
||||
EXPECT_EQ(64, img.rows);
|
||||
EXPECT_EQ(CV_8UC3, img.type()) << cv::typeToString(img.type());
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, decode_black_and_write_image_pr17275_grayscale)
|
||||
{
|
||||
const string filename = cvtest::findDataFile("readwrite/bitsperpixel1_min.tiff");
|
||||
cv::Mat img;
|
||||
ASSERT_NO_THROW(img = cv::imread(filename, IMREAD_GRAYSCALE));
|
||||
ASSERT_FALSE(img.empty());
|
||||
EXPECT_EQ(64, img.cols);
|
||||
EXPECT_EQ(64, img.rows);
|
||||
EXPECT_EQ(CV_8UC1, img.type()) << cv::typeToString(img.type());
|
||||
// Check for 0/255 values only: 267 + 3829 = 64*64
|
||||
EXPECT_EQ(267, countNonZero(img == 0));
|
||||
EXPECT_EQ(3829, countNonZero(img == 255));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, decode_black_and_write_image_pr17275_default)
|
||||
{
|
||||
const string filename = cvtest::findDataFile("readwrite/bitsperpixel1_min.tiff");
|
||||
cv::Mat img;
|
||||
ASSERT_NO_THROW(img = cv::imread(filename)); // by default image type is CV_8UC3
|
||||
ASSERT_FALSE(img.empty());
|
||||
EXPECT_EQ(64, img.cols);
|
||||
EXPECT_EQ(64, img.rows);
|
||||
EXPECT_EQ(CV_8UC3, img.type()) << cv::typeToString(img.type());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}} // namespace
|
||||
114
modules/imgcodecs/test/test_webp.cpp
Normal file
114
modules/imgcodecs/test/test_webp.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
#ifdef HAVE_WEBP
|
||||
|
||||
TEST(Imgcodecs_WebP, encode_decode_lossless_webp)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
string filename = root + "../cv/shared/lena.png";
|
||||
cv::Mat img = cv::imread(filename);
|
||||
ASSERT_FALSE(img.empty());
|
||||
|
||||
string output = cv::tempfile(".webp");
|
||||
EXPECT_NO_THROW(cv::imwrite(output, img)); // lossless
|
||||
|
||||
cv::Mat img_webp = cv::imread(output);
|
||||
|
||||
std::vector<unsigned char> buf;
|
||||
|
||||
FILE * wfile = NULL;
|
||||
|
||||
wfile = fopen(output.c_str(), "rb");
|
||||
if (wfile != NULL)
|
||||
{
|
||||
fseek(wfile, 0, SEEK_END);
|
||||
size_t wfile_size = ftell(wfile);
|
||||
fseek(wfile, 0, SEEK_SET);
|
||||
|
||||
buf.resize(wfile_size);
|
||||
|
||||
size_t data_size = fread(&buf[0], 1, wfile_size, wfile);
|
||||
|
||||
if(wfile)
|
||||
{
|
||||
fclose(wfile);
|
||||
}
|
||||
|
||||
if (data_size != wfile_size)
|
||||
{
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
|
||||
cv::Mat decode = cv::imdecode(buf, IMREAD_COLOR);
|
||||
ASSERT_FALSE(decode.empty());
|
||||
EXPECT_TRUE(cvtest::norm(decode, img_webp, NORM_INF) == 0);
|
||||
|
||||
ASSERT_FALSE(img_webp.empty());
|
||||
|
||||
EXPECT_TRUE(cvtest::norm(img, img_webp, NORM_INF) == 0);
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_WebP, encode_decode_lossy_webp)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
std::string input = root + "../cv/shared/lena.png";
|
||||
cv::Mat img = cv::imread(input);
|
||||
ASSERT_FALSE(img.empty());
|
||||
|
||||
for(int q = 100; q>=0; q-=20)
|
||||
{
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_WEBP_QUALITY);
|
||||
params.push_back(q);
|
||||
string output = cv::tempfile(".webp");
|
||||
|
||||
EXPECT_NO_THROW(cv::imwrite(output, img, params));
|
||||
cv::Mat img_webp = cv::imread(output);
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
EXPECT_FALSE(img_webp.empty());
|
||||
EXPECT_EQ(3, img_webp.channels());
|
||||
EXPECT_EQ(512, img_webp.cols);
|
||||
EXPECT_EQ(512, img_webp.rows);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_WebP, encode_decode_with_alpha_webp)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
std::string input = root + "../cv/shared/lena.png";
|
||||
cv::Mat img = cv::imread(input);
|
||||
ASSERT_FALSE(img.empty());
|
||||
|
||||
std::vector<cv::Mat> imgs;
|
||||
cv::split(img, imgs);
|
||||
imgs.push_back(cv::Mat(imgs[0]));
|
||||
imgs[imgs.size() - 1] = cv::Scalar::all(128);
|
||||
cv::merge(imgs, img);
|
||||
|
||||
string output = cv::tempfile(".webp");
|
||||
|
||||
EXPECT_NO_THROW(cv::imwrite(output, img));
|
||||
cv::Mat img_webp = cv::imread(output, IMREAD_UNCHANGED);
|
||||
cv::Mat img_webp_bgr = cv::imread(output); // IMREAD_COLOR by default
|
||||
EXPECT_EQ(0, remove(output.c_str()));
|
||||
EXPECT_FALSE(img_webp.empty());
|
||||
EXPECT_EQ(4, img_webp.channels());
|
||||
EXPECT_EQ(512, img_webp.cols);
|
||||
EXPECT_EQ(512, img_webp.rows);
|
||||
EXPECT_FALSE(img_webp_bgr.empty());
|
||||
EXPECT_EQ(3, img_webp_bgr.channels());
|
||||
EXPECT_EQ(512, img_webp_bgr.cols);
|
||||
EXPECT_EQ(512, img_webp_bgr.rows);
|
||||
}
|
||||
|
||||
#endif // HAVE_WEBP
|
||||
|
||||
}} // namespace
|
||||
Reference in New Issue
Block a user