mirror of
https://github.com/opencv/opencv.git
synced 2024-11-24 03:00:14 +08:00
Merge remote-tracking branch 'upstream/3.4' into merge-3.4
This commit is contained in:
commit
e5d78960c6
@ -62,6 +62,22 @@ CV_CPU_OPTIMIZATION_HAL_NAMESPACE_BEGIN
|
||||
#define CV_SIMD128_64F 0
|
||||
#endif
|
||||
|
||||
// The following macro checks if the code is being compiled for the
|
||||
// AArch64 execution state of Armv8, to enable the 128-bit
|
||||
// intrinsics. The macro `__ARM_64BIT_STATE` is the one recommended by
|
||||
// the Arm C Language Extension (ACLE) specifications [1] to check the
|
||||
// availability of 128-bit intrinsics, and it is supporrted by clang
|
||||
// and gcc. The macro `_M_ARM64` is the equivalent one for Microsoft
|
||||
// Visual Studio [2] .
|
||||
//
|
||||
// [1] https://developer.arm.com/documentation/101028/0012/13--Advanced-SIMD--Neon--intrinsics
|
||||
// [2] https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
#if defined(__ARM_64BIT_STATE) || defined(_M_ARM64)
|
||||
#define CV_NEON_AARCH64 1
|
||||
#else
|
||||
#define CV_NEON_AARCH64 0
|
||||
#endif
|
||||
|
||||
// TODO
|
||||
#define CV_NEON_DOT 0
|
||||
|
||||
@ -726,41 +742,61 @@ inline v_float64x2 v_dotprod_expand(const v_int32x4& a, const v_int32x4& b,
|
||||
// 16 >> 32
|
||||
inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b)
|
||||
{
|
||||
#if CV_NEON_AARCH64
|
||||
int32x4_t p = vmull_s16(vget_low_s16(a.val), vget_low_s16(b.val));
|
||||
return v_int32x4(vmlal_high_s16(p, a.val, b.val));
|
||||
#else
|
||||
int16x4_t a0 = vget_low_s16(a.val);
|
||||
int16x4_t a1 = vget_high_s16(a.val);
|
||||
int16x4_t b0 = vget_low_s16(b.val);
|
||||
int16x4_t b1 = vget_high_s16(b.val);
|
||||
int32x4_t p = vmull_s16(a0, b0);
|
||||
return v_int32x4(vmlal_s16(p, a1, b1));
|
||||
#endif
|
||||
}
|
||||
inline v_int32x4 v_dotprod_fast(const v_int16x8& a, const v_int16x8& b, const v_int32x4& c)
|
||||
{
|
||||
#if CV_NEON_AARCH64
|
||||
int32x4_t p = vmlal_s16(c.val, vget_low_s16(a.val), vget_low_s16(b.val));
|
||||
return v_int32x4(vmlal_high_s16(p, a.val, b.val));
|
||||
#else
|
||||
int16x4_t a0 = vget_low_s16(a.val);
|
||||
int16x4_t a1 = vget_high_s16(a.val);
|
||||
int16x4_t b0 = vget_low_s16(b.val);
|
||||
int16x4_t b1 = vget_high_s16(b.val);
|
||||
int32x4_t p = vmlal_s16(c.val, a0, b0);
|
||||
return v_int32x4(vmlal_s16(p, a1, b1));
|
||||
#endif
|
||||
}
|
||||
|
||||
// 32 >> 64
|
||||
inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b)
|
||||
{
|
||||
#if CV_NEON_AARCH64
|
||||
int64x2_t p = vmull_s32(vget_low_s32(a.val), vget_low_s32(b.val));
|
||||
return v_int64x2(vmlal_high_s32(p, a.val, b.val));
|
||||
#else
|
||||
int32x2_t a0 = vget_low_s32(a.val);
|
||||
int32x2_t a1 = vget_high_s32(a.val);
|
||||
int32x2_t b0 = vget_low_s32(b.val);
|
||||
int32x2_t b1 = vget_high_s32(b.val);
|
||||
int64x2_t p = vmull_s32(a0, b0);
|
||||
return v_int64x2(vmlal_s32(p, a1, b1));
|
||||
#endif
|
||||
}
|
||||
inline v_int64x2 v_dotprod_fast(const v_int32x4& a, const v_int32x4& b, const v_int64x2& c)
|
||||
{
|
||||
#if CV_NEON_AARCH64
|
||||
int64x2_t p = vmlal_s32(c.val, vget_low_s32(a.val), vget_low_s32(b.val));
|
||||
return v_int64x2(vmlal_high_s32(p, a.val, b.val));
|
||||
#else
|
||||
int32x2_t a0 = vget_low_s32(a.val);
|
||||
int32x2_t a1 = vget_high_s32(a.val);
|
||||
int32x2_t b0 = vget_low_s32(b.val);
|
||||
int32x2_t b1 = vget_high_s32(b.val);
|
||||
int64x2_t p = vmlal_s32(c.val, a0, b0);
|
||||
return v_int64x2(vmlal_s32(p, a1, b1));
|
||||
#endif
|
||||
}
|
||||
|
||||
// 8 >> 32
|
||||
@ -1292,7 +1328,7 @@ inline int64 v_reduce_sum(const v_int64x2& a)
|
||||
#if CV_SIMD128_64F
|
||||
inline double v_reduce_sum(const v_float64x2& a)
|
||||
{
|
||||
return vgetq_lane_f64(a.val, 0) + vgetq_lane_f64(a.val, 1);
|
||||
return vaddvq_f64(a.val);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -356,6 +356,16 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// Disable thread sanitization check when CV_USE_GLOBAL_WORKERS_COND_VAR is not
|
||||
// set because it triggers as the main thread reads isActive while the children
|
||||
// thread writes it (but it all works out because a mutex is locked in the main
|
||||
// thread and isActive re-checked).
|
||||
// This is to solve issue #19463.
|
||||
#if !defined(CV_USE_GLOBAL_WORKERS_COND_VAR) && defined(__clang__) && defined(__has_feature)
|
||||
#if __has_feature(thread_sanitizer)
|
||||
__attribute__((no_sanitize("thread")))
|
||||
#endif
|
||||
#endif
|
||||
void WorkerThread::thread_body()
|
||||
{
|
||||
(void)cv::utils::getThreadID(); // notify OpenCV about new thread
|
||||
|
@ -13,11 +13,6 @@ if(HAVE_WINRT_CX AND NOT WINRT)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /ZW")
|
||||
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_JPEG)
|
||||
ocv_include_directories(${JPEG_INCLUDE_DIR} ${${JPEG_LIBRARY}_BINARY_DIR})
|
||||
list(APPEND GRFMT_LIBS ${JPEG_LIBRARIES})
|
||||
@ -63,6 +58,11 @@ if(HAVE_OPENEXR)
|
||||
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})
|
||||
|
@ -62,7 +62,7 @@ ExifEntry_t::ExifEntry_t() :
|
||||
/**
|
||||
* @brief ExifReader constructor
|
||||
*/
|
||||
ExifReader::ExifReader(std::istream& stream) : m_stream(stream), m_format(NONE)
|
||||
ExifReader::ExifReader() : m_format(NONE)
|
||||
{
|
||||
}
|
||||
|
||||
@ -73,25 +73,6 @@ ExifReader::~ExifReader()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parsing the file and prepare (internally) exif directory structure
|
||||
* @return true if parsing was successful and exif information exists in JpegReader object
|
||||
* false in case of unsuccessful parsing
|
||||
*/
|
||||
bool ExifReader::parse()
|
||||
{
|
||||
try {
|
||||
m_exif = getExif();
|
||||
if( !m_exif.empty() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (ExifParsingError&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get tag value by tag number
|
||||
@ -101,10 +82,10 @@ bool ExifReader::parse()
|
||||
* @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)
|
||||
ExifEntry_t ExifReader::getTag(const ExifTagName tag) const
|
||||
{
|
||||
ExifEntry_t entry;
|
||||
std::map<int, ExifEntry_t>::iterator it = m_exif.find(tag);
|
||||
std::map<int, ExifEntry_t>::const_iterator it = m_exif.find(tag);
|
||||
|
||||
if( it != m_exif.end() )
|
||||
{
|
||||
@ -115,100 +96,37 @@ ExifEntry_t ExifReader::getTag(const ExifTagName tag)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get exif directory structure contained in file (if any)
|
||||
* This is internal function and is not exposed to client
|
||||
* @brief Parsing the exif data buffer and prepare (internal) exif directory
|
||||
*
|
||||
* @return Map where key is tag number and value is ExifEntry_t structure
|
||||
*/
|
||||
std::map<int, ExifEntry_t > ExifReader::getExif()
|
||||
{
|
||||
const std::streamsize markerSize = 2;
|
||||
const std::streamsize offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header
|
||||
unsigned char appMarker[markerSize];
|
||||
m_exif.erase( m_exif.begin(), m_exif.end() );
|
||||
|
||||
std::streamsize count;
|
||||
|
||||
bool exifFound = false, stopSearch = false;
|
||||
while( ( !m_stream.eof() ) && !exifFound && !stopSearch )
|
||||
{
|
||||
m_stream.read( reinterpret_cast<char*>(appMarker), markerSize );
|
||||
count = m_stream.gcount();
|
||||
if( count < markerSize )
|
||||
{
|
||||
break;
|
||||
}
|
||||
unsigned char marker = appMarker[1];
|
||||
size_t bytesToSkip;
|
||||
size_t exifSize;
|
||||
switch( marker )
|
||||
{
|
||||
//For all the markers just skip bytes in file pointed by followed two bytes (field size)
|
||||
case SOF0: case SOF2: case DHT: case DQT: case DRI: case SOS:
|
||||
case RST0: case RST1: case RST2: case RST3: case RST4: case RST5: case RST6: case RST7:
|
||||
case APP0: case APP2: case APP3: case APP4: case APP5: case APP6: case APP7: case APP8:
|
||||
case APP9: case APP10: case APP11: case APP12: case APP13: case APP14: case APP15:
|
||||
case COM:
|
||||
bytesToSkip = getFieldSize();
|
||||
if (bytesToSkip < markerSize) {
|
||||
throw ExifParsingError();
|
||||
}
|
||||
m_stream.seekg( static_cast<long>( bytesToSkip - markerSize ), m_stream.cur );
|
||||
if ( m_stream.fail() ) {
|
||||
throw ExifParsingError();
|
||||
}
|
||||
break;
|
||||
|
||||
//SOI and EOI don't have the size field after the marker
|
||||
case SOI: case EOI:
|
||||
break;
|
||||
|
||||
case APP1: //actual Exif Marker
|
||||
exifSize = getFieldSize();
|
||||
if (exifSize <= offsetToTiffHeader) {
|
||||
throw ExifParsingError();
|
||||
}
|
||||
m_data.resize( exifSize - offsetToTiffHeader );
|
||||
m_stream.seekg( static_cast<long>( offsetToTiffHeader ), m_stream.cur );
|
||||
if ( m_stream.fail() ) {
|
||||
throw ExifParsingError();
|
||||
}
|
||||
m_stream.read( reinterpret_cast<char*>(&m_data[0]), exifSize - offsetToTiffHeader );
|
||||
exifFound = true;
|
||||
break;
|
||||
|
||||
default: //No other markers are expected according to standard. May be a signal of error
|
||||
stopSearch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !exifFound )
|
||||
{
|
||||
return m_exif;
|
||||
}
|
||||
|
||||
parseExif();
|
||||
|
||||
return m_exif;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the size of exif field (required to properly ready whole exif from the file)
|
||||
* This is internal function and is not exposed to client
|
||||
* @param [in] data The data buffer to read EXIF data starting with endianness
|
||||
* @param [in] size The size of the data buffer
|
||||
*
|
||||
* @return size of exif field in the file
|
||||
* @return true if parsing was successful
|
||||
* false in case of unsuccessful parsing
|
||||
*/
|
||||
size_t ExifReader::getFieldSize ()
|
||||
bool ExifReader::parseExif(unsigned char* data, const size_t size)
|
||||
{
|
||||
unsigned char fieldSize[2];
|
||||
m_stream.read( reinterpret_cast<char*>(fieldSize), 2 );
|
||||
std::streamsize count = m_stream.gcount();
|
||||
if (count < 2)
|
||||
// Populate m_data, then call parseExif() (private)
|
||||
if( data && size > 0 )
|
||||
{
|
||||
return 0;
|
||||
m_data.assign(data, data + size);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
parseExif();
|
||||
if( !m_exif.empty() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch( ExifParsingError& ) {
|
||||
return false;
|
||||
}
|
||||
return ( fieldSize[0] << 8 ) + fieldSize[1];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,24 +54,6 @@
|
||||
|
||||
namespace cv
|
||||
{
|
||||
/**
|
||||
* @brief Jpeg markers that can encounter in 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
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Base Exif tags used by IFD0 (main image)
|
||||
@ -168,19 +150,22 @@ class ExifReader
|
||||
public:
|
||||
/**
|
||||
* @brief ExifReader constructor. Constructs an object of exif reader
|
||||
*
|
||||
* @param [in]stream An istream to look for EXIF bytes from
|
||||
*/
|
||||
explicit ExifReader( std::istream& stream );
|
||||
ExifReader();
|
||||
~ExifReader();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse the file with exif info
|
||||
*
|
||||
* @return true if parsing was successful and exif information exists in JpegReader object
|
||||
* @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 parse();
|
||||
|
||||
bool parseExif(unsigned char* data, const size_t size);
|
||||
|
||||
/**
|
||||
* @brief Get tag info by tag number
|
||||
@ -188,10 +173,10 @@ public:
|
||||
* @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 );
|
||||
ExifEntry_t getTag( const ExifTagName tag ) const;
|
||||
|
||||
|
||||
private:
|
||||
std::istream& m_stream;
|
||||
std::vector<unsigned char> m_data;
|
||||
std::map<int, ExifEntry_t > m_exif;
|
||||
Endianess_t m_format;
|
||||
@ -199,7 +184,6 @@ private:
|
||||
void parseExif();
|
||||
bool checkTagMark() const;
|
||||
|
||||
size_t getFieldSize ();
|
||||
size_t getNumDirEntry( const size_t offsetNumDir ) const;
|
||||
uint32_t getStartOffset() const;
|
||||
uint16_t getExifTag( const size_t offset ) const;
|
||||
@ -215,7 +199,6 @@ private:
|
||||
|
||||
u_rational_t getURational( const size_t offset ) const;
|
||||
|
||||
std::map<int, ExifEntry_t > getExif();
|
||||
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;
|
||||
|
@ -55,6 +55,11 @@ BaseImageDecoder::BaseImageDecoder()
|
||||
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;
|
||||
|
@ -45,6 +45,7 @@
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "bitstrm.hpp"
|
||||
#include "exif.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
@ -65,6 +66,7 @@ public:
|
||||
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 );
|
||||
@ -87,6 +89,7 @@ protected:
|
||||
String m_signature;
|
||||
Mat m_buf;
|
||||
bool m_buf_supported;
|
||||
ExifReader m_exif;
|
||||
};
|
||||
|
||||
|
||||
|
@ -244,6 +244,7 @@ bool JpegDecoder::readHeader()
|
||||
|
||||
if (state->cinfo.src != 0)
|
||||
{
|
||||
jpeg_save_markers(&state->cinfo, APP1, 0xffff);
|
||||
jpeg_read_header( &state->cinfo, TRUE );
|
||||
|
||||
state->cinfo.scale_num=1;
|
||||
@ -456,6 +457,29 @@ bool JpegDecoder::readData( Mat& img )
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
|
@ -52,6 +52,25 @@
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -284,6 +284,22 @@ bool PngDecoder::readData( Mat& img )
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -361,48 +361,15 @@ static void ExifTransform(int orientation, Mat& img)
|
||||
}
|
||||
}
|
||||
|
||||
static void ApplyExifOrientation(const String& filename, Mat& img)
|
||||
static void ApplyExifOrientation(ExifEntry_t orientationTag, Mat& img)
|
||||
{
|
||||
int orientation = IMAGE_ORIENTATION_TL;
|
||||
|
||||
if (filename.size() > 0)
|
||||
if (orientationTag.tag != INVALID_TAG)
|
||||
{
|
||||
std::ifstream stream( filename.c_str(), std::ios_base::in | std::ios_base::binary );
|
||||
ExifReader reader( stream );
|
||||
if( reader.parse() )
|
||||
{
|
||||
ExifEntry_t entry = reader.getTag( ORIENTATION );
|
||||
if (entry.tag != INVALID_TAG)
|
||||
{
|
||||
orientation = entry.field_u16; //orientation is unsigned short, so check field_u16
|
||||
}
|
||||
}
|
||||
stream.close();
|
||||
orientation = orientationTag.field_u16; //orientation is unsigned short, so check field_u16
|
||||
ExifTransform(orientation, img);
|
||||
}
|
||||
|
||||
ExifTransform(orientation, img);
|
||||
}
|
||||
|
||||
static void ApplyExifOrientation(const Mat& buf, Mat& img)
|
||||
{
|
||||
int orientation = IMAGE_ORIENTATION_TL;
|
||||
|
||||
if( buf.isContinuous() )
|
||||
{
|
||||
ByteStreamBuffer bsb( reinterpret_cast<char*>(buf.data), buf.total() * buf.elemSize() );
|
||||
std::istream stream( &bsb );
|
||||
ExifReader reader( stream );
|
||||
if( reader.parse() )
|
||||
{
|
||||
ExifEntry_t entry = reader.getTag( ORIENTATION );
|
||||
if (entry.tag != INVALID_TAG)
|
||||
{
|
||||
orientation = entry.field_u16; //orientation is unsigned short, so check field_u16
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExifTransform(orientation, img);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -518,6 +485,12 @@ imread_( const String& filename, int flags, Mat& mat )
|
||||
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;
|
||||
}
|
||||
|
||||
@ -614,7 +587,7 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
|
||||
// optionally rotate the data if EXIF' orientation flag says so
|
||||
if( (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
|
||||
{
|
||||
ApplyExifOrientation(filename, mat);
|
||||
ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
|
||||
}
|
||||
|
||||
mats.push_back(mat);
|
||||
@ -645,12 +618,6 @@ Mat imread( const String& filename, int flags )
|
||||
/// load the data
|
||||
imread_( filename, flags, img );
|
||||
|
||||
/// optionally rotate the data if EXIF' orientation flag says so
|
||||
if( !img.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
|
||||
{
|
||||
ApplyExifOrientation(filename, img);
|
||||
}
|
||||
|
||||
/// return a reference to the data
|
||||
return img;
|
||||
}
|
||||
@ -889,6 +856,12 @@ imdecode_( const Mat& buf, int flags, Mat& mat )
|
||||
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;
|
||||
}
|
||||
|
||||
@ -900,12 +873,6 @@ Mat imdecode( InputArray _buf, int flags )
|
||||
Mat buf = _buf.getMat(), img;
|
||||
imdecode_( buf, flags, img );
|
||||
|
||||
/// optionally rotate the data if EXIF' orientation flag says so
|
||||
if( !img.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
|
||||
{
|
||||
ApplyExifOrientation(buf, img);
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
@ -917,12 +884,6 @@ Mat imdecode( InputArray _buf, int flags, Mat* dst )
|
||||
dst = dst ? dst : &img;
|
||||
imdecode_( buf, flags, *dst );
|
||||
|
||||
/// optionally rotate the data if EXIF' orientation flag says so
|
||||
if( !dst->empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
|
||||
{
|
||||
ApplyExifOrientation(buf, *dst);
|
||||
}
|
||||
|
||||
return *dst;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,12 @@ namespace opencv_test { namespace {
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
|
||||
#ifdef HAVE_LIBPNG_PNG_H
|
||||
#include <libpng/png.h>
|
||||
#else
|
||||
#include <png.h>
|
||||
#endif
|
||||
|
||||
TEST(Imgcodecs_Png, write_big)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
@ -93,6 +99,97 @@ TEST(Imgcodecs_Png, read_color_palette_with_alpha)
|
||||
EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
|
||||
}
|
||||
|
||||
#ifdef PNG_eXIf_SUPPORTED
|
||||
/**
|
||||
* 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
|
||||
TEST_P(Imgcodecs_PNG_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.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 // PNG_eXIf_SUPPORTED
|
||||
|
||||
#endif // HAVE_PNG
|
||||
|
||||
}} // namespace
|
||||
|
@ -19,7 +19,7 @@ namespace ocl {
|
||||
|
||||
typedef TestBaseWithParam<string> stitch;
|
||||
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
#if defined(HAVE_OPENCV_XFEATURES2D) && defined(OPENCV_ENABLE_NONFREE)
|
||||
#define TEST_DETECTORS testing::Values("surf", "orb", "akaze")
|
||||
#else
|
||||
#define TEST_DETECTORS testing::Values("orb", "akaze")
|
||||
|
@ -8,7 +8,7 @@ using namespace perf;
|
||||
|
||||
typedef TestBaseWithParam<tuple<string, string> > bundleAdjuster;
|
||||
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
#if defined(HAVE_OPENCV_XFEATURES2D) && defined(OPENCV_ENABLE_NONFREE)
|
||||
#define TEST_DETECTORS testing::Values("surf", "orb")
|
||||
#else
|
||||
#define TEST_DETECTORS testing::Values<string>("orb")
|
||||
|
@ -17,7 +17,7 @@ typedef TestBaseWithParam<matchVector_t> matchVector;
|
||||
#define ORB_MATCH_CONFIDENCE 0.3f
|
||||
#define WORK_MEGAPIX 0.6
|
||||
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
#if defined(HAVE_OPENCV_XFEATURES2D) && defined(OPENCV_ENABLE_NONFREE)
|
||||
#define TEST_DETECTORS testing::Values("surf", "orb")
|
||||
#else
|
||||
#define TEST_DETECTORS testing::Values<string>("orb")
|
||||
|
@ -15,7 +15,7 @@ static inline Ptr<Feature2D> getFeatureFinder(const std::string& name)
|
||||
{
|
||||
if (name == "orb")
|
||||
return ORB::create();
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
#if defined(HAVE_OPENCV_XFEATURES2D) && defined(OPENCV_ENABLE_NONFREE)
|
||||
else if (name == "surf")
|
||||
return xfeatures2d::SURF::create();
|
||||
#endif
|
||||
|
@ -17,7 +17,7 @@ typedef TestBaseWithParam<int> stitchExposureCompensation;
|
||||
typedef TestBaseWithParam<tuple<string, string> > stitchDatasets;
|
||||
typedef TestBaseWithParam<tuple<string, int>> stitchExposureCompMultiFeed;
|
||||
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
#if defined(HAVE_OPENCV_XFEATURES2D) && defined(OPENCV_ENABLE_NONFREE)
|
||||
#define TEST_DETECTORS testing::Values("surf", "orb", "akaze")
|
||||
#else
|
||||
#define TEST_DETECTORS testing::Values("orb", "akaze")
|
||||
|
@ -248,7 +248,7 @@ if __name__ == "__main__":
|
||||
|
||||
log.debug("Args: %s", args)
|
||||
|
||||
os.environ["OPENCV_JS_WHITELIST"] = args.config
|
||||
os.environ["OPENCV_JS_WHITELIST"] = os.path.abspath(args.config)
|
||||
|
||||
if 'EMMAKEN_JUST_CONFIGURE' in os.environ:
|
||||
del os.environ['EMMAKEN_JUST_CONFIGURE'] # avoid linker errors with NODERAWFS message then using 'emcmake' launcher
|
||||
|
@ -24,23 +24,16 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Show source image
|
||||
// Show the source image
|
||||
imshow("Source Image", src);
|
||||
//! [load_image]
|
||||
|
||||
//! [black_bg]
|
||||
// Change the background from white to black, since that will help later to extract
|
||||
// better results during the use of Distance Transform
|
||||
for ( int i = 0; i < src.rows; i++ ) {
|
||||
for ( int j = 0; j < src.cols; j++ ) {
|
||||
if ( src.at<Vec3b>(i, j) == Vec3b(255,255,255) )
|
||||
{
|
||||
src.at<Vec3b>(i, j)[0] = 0;
|
||||
src.at<Vec3b>(i, j)[1] = 0;
|
||||
src.at<Vec3b>(i, j)[2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Mat mask;
|
||||
inRange(src, Scalar(255, 255, 255), Scalar(255, 255, 255), mask);
|
||||
src.setTo(Scalar(0, 0, 0), mask);
|
||||
|
||||
// Show output image
|
||||
imshow("Black Background Image", src);
|
||||
@ -124,7 +117,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Draw the background marker
|
||||
circle(markers, Point(5,5), 3, Scalar(255), -1);
|
||||
imshow("Markers", markers*10000);
|
||||
Mat markers8u;
|
||||
markers.convertTo(markers8u, CV_8U, 10);
|
||||
imshow("Markers", markers8u);
|
||||
//! [seeds]
|
||||
|
||||
//! [watershed]
|
||||
|
@ -102,7 +102,8 @@ for i in range(len(contours)):
|
||||
|
||||
# Draw the background marker
|
||||
cv.circle(markers, (5,5), 3, (255,255,255), -1)
|
||||
cv.imshow('Markers', markers*10000)
|
||||
markers_8u = (markers * 10).astype('uint8')
|
||||
cv.imshow('Markers', markers_8u)
|
||||
## [seeds]
|
||||
|
||||
## [watershed]
|
||||
|
Loading…
Reference in New Issue
Block a user