Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
0a306f88
Commit
0a306f88
authored
Oct 11, 2015
by
micalan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Camera orientation handling is added for jpeg files
parent
d430e802
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1042 additions
and
0 deletions
+1042
-0
CMakeLists.txt
modules/imgcodecs/CMakeLists.txt
+2
-0
grfmt_jpeg.cpp
modules/imgcodecs/src/grfmt_jpeg.cpp
+56
-0
grfmt_jpeg.hpp
modules/imgcodecs/src/grfmt_jpeg.hpp
+6
-0
jpeg_exif.cpp
modules/imgcodecs/src/jpeg_exif.cpp
+582
-0
jpeg_exif.hpp
modules/imgcodecs/src/jpeg_exif.hpp
+251
-0
test_grfmt.cpp
modules/imgcodecs/test/test_grfmt.cpp
+145
-0
No files found.
modules/imgcodecs/CMakeLists.txt
View file @
0a306f88
...
...
@@ -61,6 +61,8 @@ 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/jpeg_exif.hpp
)
list
(
APPEND grfmt_srcs
${
CMAKE_CURRENT_LIST_DIR
}
/src/jpeg_exif.cpp
)
source_group
(
"Src
\\
grfmts"
FILES
${
grfmt_hdrs
}
${
grfmt_srcs
}
)
...
...
modules/imgcodecs/src/grfmt_jpeg.cpp
View file @
0a306f88
...
...
@@ -41,6 +41,7 @@
#include "precomp.hpp"
#include "grfmt_jpeg.hpp"
#include "jpeg_exif.hpp"
#ifdef HAVE_JPEG
...
...
@@ -177,6 +178,7 @@ JpegDecoder::JpegDecoder()
m_state
=
0
;
m_f
=
0
;
m_buf_supported
=
true
;
m_orientation
=
JPEG_ORIENTATION_TL
;
}
...
...
@@ -253,12 +255,64 @@ bool JpegDecoder::readHeader()
}
}
m_orientation
=
getOrientation
();
if
(
!
result
)
close
();
return
result
;
}
int
JpegDecoder
::
getOrientation
()
{
int
orientation
=
JPEG_ORIENTATION_TL
;
ExifReader
reader
(
m_filename
);
if
(
reader
.
parse
()
)
{
orientation
=
reader
.
getTag
(
ORIENTATION
).
field_u16
;
//orientation is unsigned short, so check field_u16
}
return
orientation
;
}
void
JpegDecoder
::
setOrientation
(
Mat
&
img
)
{
switch
(
m_orientation
)
{
case
JPEG_ORIENTATION_TL
:
//0th row == visual top, 0th column == visual left-hand side
//do nothing, the image already has proper orientation
break
;
case
JPEG_ORIENTATION_TR
:
//0th row == visual top, 0th column == visual right-hand side
flip
(
img
,
img
,
1
);
//flip horizontally
break
;
case
JPEG_ORIENTATION_BR
:
//0th row == visual bottom, 0th column == visual right-hand side
flip
(
img
,
img
,
-
1
);
//flip both horizontally and vertically
break
;
case
JPEG_ORIENTATION_BL
:
//0th row == visual bottom, 0th column == visual left-hand side
flip
(
img
,
img
,
0
);
//flip vertically
break
;
case
JPEG_ORIENTATION_LT
:
//0th row == visual left-hand side, 0th column == visual top
transpose
(
img
,
img
);
break
;
case
JPEG_ORIENTATION_RT
:
//0th row == visual right-hand side, 0th column == visual top
transpose
(
img
,
img
);
flip
(
img
,
img
,
1
);
//flip horizontally
break
;
case
JPEG_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
JPEG_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
;
}
}
/***************************************************************************
* following code is for supporting MJPEG image files
* based on a message of Laurent Pinchart on the video4linux mailing list
...
...
@@ -472,8 +526,10 @@ bool JpegDecoder::readData( Mat& img )
icvCvt_CMYK2Gray_8u_C4C1R
(
buffer
[
0
],
0
,
data
,
0
,
cvSize
(
m_width
,
1
)
);
}
}
result
=
true
;
jpeg_finish_decompress
(
cinfo
);
setOrientation
(
img
);
}
}
...
...
modules/imgcodecs/src/grfmt_jpeg.hpp
View file @
0a306f88
...
...
@@ -70,6 +70,12 @@ protected:
FILE
*
m_f
;
void
*
m_state
;
private
:
//Support for handling exif orientation tag in Jpeg file
int
m_orientation
;
int
getOrientation
();
void
setOrientation
(
Mat
&
img
);
};
...
...
modules/imgcodecs/src/jpeg_exif.cpp
0 → 100644
View file @
0a306f88
/*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 "jpeg_exif.hpp"
namespace
cv
{
/**
* @brief ExifReader constructor
*/
ExifReader
::
ExifReader
(
std
::
string
filename
)
:
m_filename
(
filename
)
{
}
/**
* @brief ExifReader destructor
*/
ExifReader
::~
ExifReader
()
{
}
/**
* @brief Parsing the jpeg 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
()
{
m_exif
=
getExif
();
if
(
!
m_exif
.
empty
()
)
{
return
true
;
}
return
false
;
}
/**
* @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
)
{
ExifEntry_t
entry
;
std
::
map
<
int
,
ExifEntry_t
>::
iterator
it
=
m_exif
.
find
(
tag
);
if
(
it
!=
m_exif
.
end
()
)
{
entry
=
it
->
second
;
}
return
entry
;
}
/**
* @brief Get exif directory structure contained in jpeg file (if any)
* This is internal function and is not exposed to client
*
* @return Map where key is tag number and value is ExifEntry_t structure
*/
std
::
map
<
int
,
ExifEntry_t
>
ExifReader
::
getExif
()
{
const
size_t
markerSize
=
2
;
const
size_t
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
()
);
size_t
count
;
FILE
*
f
=
fopen
(
m_filename
.
c_str
(),
"rb"
);
if
(
!
f
)
{
return
m_exif
;
//Until this moment the map is empty
}
bool
exifFound
=
false
;
while
(
(
!
feof
(
f
)
)
&&
!
exifFound
)
{
count
=
fread
(
appMarker
,
sizeof
(
unsigned
char
),
markerSize
,
f
);
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
(
f
);
fseek
(
f
,
static_cast
<
long
>
(
bytesToSkip
-
markerSize
),
SEEK_CUR
);
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
(
f
);
m_data
.
resize
(
exifSize
-
offsetToTiffHeader
);
fseek
(
f
,
static_cast
<
long
>
(
offsetToTiffHeader
),
SEEK_CUR
);
count
=
fread
(
&
m_data
[
0
],
sizeof
(
unsigned
char
),
exifSize
-
offsetToTiffHeader
,
f
);
exifFound
=
true
;
break
;
default
:
//No other markers are expected according to standard. May be a signal of error
break
;
}
}
fclose
(
f
);
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
*
* @return size of exif field in the file
*/
size_t
ExifReader
::
getFieldSize
(
FILE
*
f
)
const
{
unsigned
char
fieldSize
[
2
];
size_t
count
=
fread
(
fieldSize
,
sizeof
(
char
),
2
,
f
);
if
(
count
<
2
)
{
return
0
;
}
return
(
fieldSize
[
0
]
<<
8
)
+
fieldSize
[
1
];
}
/**
* @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 unsiccessful 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
+=
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
[
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
{
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
);
}
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
(
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
(
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
{
u_rational_t
result
;
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
modules/imgcodecs/src/jpeg_exif.hpp
0 → 100644
View file @
0a306f88
/*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_JPEG_EXIF_HPP_
#define _OPENCV_JPEG_EXIF_HPP_
#include <cstdio>
#include <map>
#include <utility>
#include <algorithm>
#include <stdint.h>
#include <string>
#include <vector>
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)
*/
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
{
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 JPEG's 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
JpegOrientation
{
JPEG_ORIENTATION_TL
=
1
,
///< 0th row == visual top, 0th column == visual left-hand side
JPEG_ORIENTATION_TR
=
2
,
///< 0th row == visual top, 0th column == visual right-hand side
JPEG_ORIENTATION_BR
=
3
,
///< 0th row == visual bottom, 0th column == visual right-hand side
JPEG_ORIENTATION_BL
=
4
,
///< 0th row == visual bottom, 0th column == visual left-hand side
JPEG_ORIENTATION_LT
=
5
,
///< 0th row == visual left-hand side, 0th column == visual top
JPEG_ORIENTATION_RT
=
6
,
///< 0th row == visual right-hand side, 0th column == visual top
JPEG_ORIENTATION_RB
=
7
,
///< 0th row == visual right-hand side, 0th column == visual bottom
JPEG_ORIENTATION_LB
=
8
///< 0th row == visual left-hand side, 0th column == visual bottom
};
/**
* @brief Reading exif information from Jpeg file
*
* Usage example for getting the orientation of the image:
*
* @code
* ExifReader reader(fileName);
* if( reader.parse() )
* {
* int orientation = reader.getTag(Orientation).field_u16;
* }
* @endcode
*
*/
class
ExifReader
{
public
:
/**
* @brief ExifReader constructor. Constructs an object of exif reader
*
* @param [in]filename The name of file to look exif info in
*/
explicit
ExifReader
(
std
::
string
filename
);
~
ExifReader
();
/**
* @brief Parse the file with exif info
*
* @return true if parsing was successful and exif information exists in JpegReader object
*/
bool
parse
();
/**
* @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
);
private
:
std
::
string
m_filename
;
std
::
vector
<
unsigned
char
>
m_data
;
std
::
map
<
int
,
ExifEntry_t
>
m_exif
;
Endianess_t
m_format
;
void
parseExif
();
bool
checkTagMark
()
const
;
size_t
getFieldSize
(
FILE
*
f
)
const
;
size_t
getNumDirEntry
()
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
::
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
;
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
;
//offset to the _number-of-directory-entry_ field
static
const
size_t
offsetNumDir
=
8
;
//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
/* JPEG_EXIF_HPP_ */
modules/imgcodecs/test/test_grfmt.cpp
View file @
0a306f88
...
...
@@ -43,6 +43,7 @@
#include "test_precomp.hpp"
#include <fstream>
#include <sstream>
using
namespace
cv
;
using
namespace
std
;
...
...
@@ -118,6 +119,150 @@ TEST(Imgcodecs_imread, regression)
}
}
template
<
class
T
>
string
to_string
(
T
i
)
{
stringstream
ss
;
string
s
;
ss
<<
i
;
s
=
ss
.
str
();
return
s
;
}
/**
* 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 |
* ---------
*
*/
class
CV_GrfmtJpegExifOrientationTest
:
public
cvtest
::
BaseTest
{
public
:
void
run
(
int
)
{
try
{
for
(
int
i
=
1
;
i
<=
8
;
++
i
)
{
string
fileName
=
"readwrite/testExifOrientation_"
+
to_string
(
i
)
+
".jpg"
;
m_img
=
imread
(
string
(
ts
->
get_data_path
())
+
fileName
);
if
(
!
m_img
.
data
)
{
ts
->
set_failed_test_info
(
cvtest
::
TS
::
FAIL_MISSING_TEST_DATA
);
}
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"start reading image
\t
%s
\n
"
,
fileName
.
c_str
());
if
(
!
checkOrientation
()
)
{
ts
->
set_failed_test_info
(
cvtest
::
TS
::
FAIL_MISMATCH
);
}
}
}
catch
(...)
{
ts
->
set_failed_test_info
(
cvtest
::
TS
::
FAIL_EXCEPTION
);
}
}
private
:
bool
checkOrientation
();
Mat
m_img
;
};
bool
CV_GrfmtJpegExifOrientationTest
::
checkOrientation
()
{
Vec3b
vec
;
int
red
=
0
;
int
green
=
0
;
int
blue
=
0
;
const
int
colorThresholdHigh
=
250
;
const
int
colorThresholdLow
=
5
;
//Checking the first quadrant (with supposed red)
vec
=
m_img
.
at
<
Vec3b
>
(
2
,
2
);
//some point inside the square
red
=
vec
.
val
[
2
];
green
=
vec
.
val
[
1
];
blue
=
vec
.
val
[
0
];
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"RED QUADRANT:
\n
"
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Red calculated:
\t\t
%d
\n
"
,
red
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Green calculated:
\t
%d
\n
"
,
green
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Blue calculated:
\t
%d
\n
"
,
blue
);
if
(
red
<
colorThresholdHigh
)
return
false
;
if
(
blue
>
colorThresholdLow
)
return
false
;
if
(
green
>
colorThresholdLow
)
return
false
;
//Checking the second quadrant (with supposed green)
vec
=
m_img
.
at
<
Vec3b
>
(
2
,
7
);
//some point inside the square
red
=
vec
.
val
[
2
];
green
=
vec
.
val
[
1
];
blue
=
vec
.
val
[
0
];
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"GREEN QUADRANT:
\n
"
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Red calculated:
\t\t
%d
\n
"
,
red
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Green calculated:
\t
%d
\n
"
,
green
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Blue calculated:
\t
%d
\n
"
,
blue
);
if
(
green
<
colorThresholdHigh
)
return
false
;
if
(
red
>
colorThresholdLow
)
return
false
;
if
(
blue
>
colorThresholdLow
)
return
false
;
//Checking the third quadrant (with supposed blue)
vec
=
m_img
.
at
<
Vec3b
>
(
7
,
2
);
//some point inside the square
red
=
vec
.
val
[
2
];
green
=
vec
.
val
[
1
];
blue
=
vec
.
val
[
0
];
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"BLUE QUADRANT:
\n
"
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Red calculated:
\t\t
%d
\n
"
,
red
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Green calculated:
\t
%d
\n
"
,
green
);
ts
->
printf
(
cvtest
::
TS
::
LOG
,
"Blue calculated:
\t
%d
\n
"
,
blue
);
if
(
blue
<
colorThresholdHigh
)
return
false
;
if
(
red
>
colorThresholdLow
)
return
false
;
if
(
green
>
colorThresholdLow
)
return
false
;
return
true
;
}
TEST
(
Imgcodecs_jpeg_exif
,
setOrientation
)
{
CV_GrfmtJpegExifOrientationTest
test
;
test
.
safe_run
();
}
#ifdef HAVE_JASPER
TEST
(
Imgcodecs_jasper
,
regression
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment