Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Opencv
提交
0a306f88
O
Opencv
项目概览
Greenplum
/
Opencv
大约 1 年 前同步成功
通知
7
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
O
Opencv
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
0a306f88
编写于
10月 11, 2015
作者:
M
micalan
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Camera orientation handling is added for jpeg files
上级
d430e802
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
1042 addition
and
0 deletion
+1042
-0
modules/imgcodecs/CMakeLists.txt
modules/imgcodecs/CMakeLists.txt
+2
-0
modules/imgcodecs/src/grfmt_jpeg.cpp
modules/imgcodecs/src/grfmt_jpeg.cpp
+56
-0
modules/imgcodecs/src/grfmt_jpeg.hpp
modules/imgcodecs/src/grfmt_jpeg.hpp
+6
-0
modules/imgcodecs/src/jpeg_exif.cpp
modules/imgcodecs/src/jpeg_exif.cpp
+582
-0
modules/imgcodecs/src/jpeg_exif.hpp
modules/imgcodecs/src/jpeg_exif.hpp
+251
-0
modules/imgcodecs/test/test_grfmt.cpp
modules/imgcodecs/test/test_grfmt.cpp
+145
-0
未找到文件。
modules/imgcodecs/CMakeLists.txt
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录