forked from mia/Aegisub
Add RGB <-> YCbCr conversion stuff to libaegisub
This commit is contained in:
parent
9774352a77
commit
cddefd8ed9
5 changed files with 197 additions and 1 deletions
|
@ -84,6 +84,7 @@
|
|||
<ClInclude Include="$(SrcDir)include\libaegisub\util.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\util_osx.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\vfr.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\ycbcr_conv.h" />
|
||||
<ClInclude Include="$(SrcDir)lagi_pre.h" />
|
||||
<ClInclude Include="$(SrcDir)lua\modules\lpeg.h" />
|
||||
</ItemGroup>
|
||||
|
@ -120,6 +121,7 @@
|
|||
<ClCompile Include="$(SrcDir)common\thesaurus.cpp" />
|
||||
<ClCompile Include="$(SrcDir)common\util.cpp" />
|
||||
<ClCompile Include="$(SrcDir)common\vfr.cpp" />
|
||||
<ClCompile Include="$(SrcDir)common\ycbcr_conv.cpp" />
|
||||
<ClCompile Include="$(SrcDir)lua\modules.cpp" />
|
||||
<ClCompile Include="$(SrcDir)lua\modules\lfs.cpp" />
|
||||
<ClCompile Include="$(SrcDir)lua\modules\lpeg.c">
|
||||
|
|
|
@ -191,6 +191,9 @@
|
|||
<ClInclude Include="$(SrcDir)include\libaegisub\lua\modules.h">
|
||||
<Filter>Lua</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\ycbcr_conv.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(SrcDir)windows\lagi_pre.cpp">
|
||||
|
@ -322,6 +325,9 @@
|
|||
<ClCompile Include="$(SrcDir)lua\modules\unicode.cpp">
|
||||
<Filter>Lua\Modules</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(SrcDir)common\ycbcr_conv.cpp">
|
||||
<Filter>Source Files\Common</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="$(SrcDir)include\libaegisub\charsets.def">
|
||||
|
|
|
@ -41,6 +41,7 @@ SRC += \
|
|||
common/thesaurus.cpp \
|
||||
common/util.cpp \
|
||||
common/vfr.cpp \
|
||||
common/ycbcr_conv.cpp \
|
||||
lua/modules.cpp \
|
||||
lua/modules/lfs.cpp \
|
||||
lua/modules/lpeg.c \
|
||||
|
|
98
libaegisub/common/ycbcr_conv.cpp
Normal file
98
libaegisub/common/ycbcr_conv.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
//
|
||||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
#include "libaegisub/ycbcr_conv.h"
|
||||
|
||||
namespace {
|
||||
double matrix_coefficients[][3] = {
|
||||
{.299, .587, .114}, // BT.601
|
||||
{.2126, .7152, .0722}, // BT.709
|
||||
{.3, .59, .11}, // FCC
|
||||
{.212, .701, .087}, // SMPTE 240M
|
||||
};
|
||||
|
||||
void row_mult(std::array<double, 9>& arr, std::array<double, 3> values) {
|
||||
size_t i = 0;
|
||||
for (auto v : values) {
|
||||
arr[i++] *= v;
|
||||
arr[i++] *= v;
|
||||
arr[i++] *= v;
|
||||
}
|
||||
}
|
||||
|
||||
void col_mult(std::array<double, 9>& m, std::array<double, 3> v) {
|
||||
m = {{
|
||||
m[0] * v[0], m[1] * v[1], m[2] * v[2],
|
||||
m[3] * v[0], m[4] * v[1], m[5] * v[2],
|
||||
m[6] * v[0], m[7] * v[1], m[8] * v[2],
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
namespace agi {
|
||||
void ycbcr_converter::init_src(ycbcr_matrix src_mat, ycbcr_range src_range) {
|
||||
auto coeff = matrix_coefficients[(int)src_mat];
|
||||
double Kr = coeff[0];
|
||||
double Kg = coeff[1];
|
||||
double Kb = coeff[2];
|
||||
to_ycbcr = {{
|
||||
Kr, Kg, Kb,
|
||||
-Kr/(1-Kb), -Kg/(1-Kb), 1,
|
||||
1, -Kg/(1-Kr), -Kb/(1-Kr),
|
||||
}};
|
||||
|
||||
if (src_range == ycbcr_range::pc) {
|
||||
row_mult(to_ycbcr, {{1., .5, .5}});
|
||||
shift_to = {{0, 128., 128.}};
|
||||
}
|
||||
else {
|
||||
row_mult(to_ycbcr, {{219./255., 112./255., 112./255.}});
|
||||
shift_to = {{16., 128., 128.}};
|
||||
}
|
||||
}
|
||||
|
||||
void ycbcr_converter::init_dst(ycbcr_matrix dst_mat, ycbcr_range dst_range) {
|
||||
auto coeff = matrix_coefficients[(int)dst_mat];
|
||||
double Kr = coeff[0];
|
||||
double Kg = coeff[1];
|
||||
double Kb = coeff[2];
|
||||
from_ycbcr = {{
|
||||
1, 0, (1-Kr),
|
||||
1, -(1-Kb)*Kb/Kg, -(1-Kr)*Kr/Kg,
|
||||
1, (1-Kb), 0,
|
||||
}};
|
||||
|
||||
if (dst_range == ycbcr_range::pc) {
|
||||
col_mult(from_ycbcr, {{1., 2., 2.}});
|
||||
shift_from = {{0, -128., -128.}};
|
||||
}
|
||||
else {
|
||||
col_mult(from_ycbcr, {{255./219., 255./112., 255./112.}});
|
||||
shift_from = {{-16., -128., -128.}};
|
||||
}
|
||||
}
|
||||
|
||||
ycbcr_converter::ycbcr_converter(ycbcr_matrix mat, ycbcr_range range) {
|
||||
init_src(mat, range);
|
||||
init_dst(mat, range);
|
||||
}
|
||||
|
||||
ycbcr_converter::ycbcr_converter(ycbcr_matrix src_mat, ycbcr_range src_range, ycbcr_matrix dst_mat, ycbcr_range dst_range) {
|
||||
init_src(src_mat, src_range);
|
||||
init_dst(dst_mat, dst_range);
|
||||
}
|
||||
}
|
||||
|
89
libaegisub/include/libaegisub/ycbcr_conv.h
Normal file
89
libaegisub/include/libaegisub/ycbcr_conv.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
//
|
||||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace agi {
|
||||
enum class ycbcr_matrix {
|
||||
bt601,
|
||||
bt709,
|
||||
fcc,
|
||||
smpte_240m
|
||||
};
|
||||
|
||||
enum class ycbcr_range {
|
||||
tv,
|
||||
pc
|
||||
};
|
||||
|
||||
/// A converter between YCbCr colorspaces and RGB
|
||||
class ycbcr_converter {
|
||||
std::array<double, 9> from_ycbcr;
|
||||
std::array<double, 9> to_ycbcr;
|
||||
|
||||
std::array<double, 3> shift_from;
|
||||
std::array<double, 3> shift_to;
|
||||
|
||||
void init_dst(ycbcr_matrix dst_mat, ycbcr_range dst_range);
|
||||
void init_src(ycbcr_matrix src_mat, ycbcr_range src_range);
|
||||
|
||||
template<typename T>
|
||||
static std::array<double, 3> prod(std::array<double, 9> m, std::array<T, 3> v) {
|
||||
return {{
|
||||
m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
|
||||
m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
|
||||
m[6] * v[0] + m[7] * v[1] + m[8] * v[2],
|
||||
}};
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
static std::array<double, 3> add(std::array<T, 3> left, std::array<U, 3> right) {
|
||||
return {{left[0] + right[0], left[1] + right[1], left[2] + right[2]}};
|
||||
}
|
||||
|
||||
static uint8_t clamp(double v) {
|
||||
auto i = static_cast<int>(v);
|
||||
i = i > 255 ? 255 : i;
|
||||
return i < 0 ? 0 : i;
|
||||
}
|
||||
|
||||
static std::array<uint8_t, 3> to_uint8_t(std::array<double, 3> val) {
|
||||
return {{clamp(val[0] + .5), clamp(val[1] + .5), clamp(val[2] + .5)}};
|
||||
}
|
||||
|
||||
public:
|
||||
ycbcr_converter(ycbcr_matrix mat, ycbcr_range range);
|
||||
ycbcr_converter(ycbcr_matrix src_mat, ycbcr_range src_range, ycbcr_matrix dst_mat, ycbcr_range dst_range);
|
||||
|
||||
/// Convert from rgb to dst_mat/dst_range
|
||||
std::array<uint8_t, 3> rgb_to_ycbcr(std::array<uint8_t, 3> input) const {
|
||||
return to_uint8_t(add(prod(to_ycbcr, input), shift_to));
|
||||
}
|
||||
|
||||
/// Convert from src_mat/src_range to rgb
|
||||
std::array<uint8_t, 3> ycbcr_to_rgb(std::array<uint8_t, 3> input) const {
|
||||
return to_uint8_t(prod(from_ycbcr, add(input, shift_from)));
|
||||
}
|
||||
|
||||
/// Convert rgb to ycbcr using src_mat and then back using dst_mat
|
||||
std::array<uint8_t, 3> rgb_to_rgb(std::array<uint8_t, 3> input) const {
|
||||
return to_uint8_t(prod(from_ycbcr,
|
||||
add(add(prod(to_ycbcr, input), shift_to), shift_from)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in a new issue