Files
calyp/lib/CalypPixel.cpp
T

186 lines
5.8 KiB
C++

/* This file is a part of Calyp project
* Copyright (C) 2014-2021 by Joao Carreira (jfmcarreira@gmail.com)
* Luis Lucas (luisfrlucas@gmail.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/**
* \file CalypFrame.cpp
* \brief Video Frame handling
*/
#include <algorithm>
#include <cassert>
#include "CalypFrame.h"
namespace
{
constexpr auto kMinPixelValue{ 0 };
constexpr auto kMaxPixelValue{ 255 };
constexpr void yuvToRgb( int iY, int iU, int iV, int& iR, int& iG, int& iB )
{
iR = std::clamp( iY + ( ( 1436 * ( iV - 128 ) ) >> 10 ), kMinPixelValue, kMaxPixelValue ); // NOLINT
iG = std::clamp( iY - ( ( 352 * ( iU - 128 ) + 731 * ( iV - 128 ) ) >> 10 ), kMinPixelValue,
kMaxPixelValue ); // NOLINT
iB = std::clamp( iY + ( ( 1812 * ( iU - 128 ) ) >> 10 ), kMinPixelValue, kMaxPixelValue ); // NOLINT
}
constexpr void rgbToYuv( int iR, int iG, int iB, int& iY, int& iU, int& iV )
{
iY = ( 299 * iR + 587 * iG + 114 * iB + 500 ) / 1000; // NOLINT
iU = ( 1000 * ( iB - iY ) + 226816 ) / 1772; // NOLINT
iV = ( 1000 * ( iR - iY ) + 179456 ) / 1402; // NOLINT
}
} // namespace
CalypPixel::CalypPixel( int colorSpace, const ClpPel c0 ) : m_colorSpace( colorSpace )
{
m_pelComp[0] = c0;
}
CalypPixel::CalypPixel( int colorSpace, const ClpPel c0, const ClpPel c1, const ClpPel c2 ) : m_colorSpace( colorSpace )
{
m_pelComp[0] = c0;
m_pelComp[1] = c1;
m_pelComp[2] = c2;
}
CalypPixel::CalypPixel( int colorSpace, const ClpPel c0, const ClpPel c1, const ClpPel c2, const ClpPel c3 )
: m_colorSpace( colorSpace )
{
m_pelComp[0] = c0;
m_pelComp[1] = c1;
m_pelComp[2] = c2;
m_pelComp[3] = c3;
}
auto CalypPixel::operator+=( const CalypPixel& in ) -> CalypPixel&
{
assert( in.colorSpace() == m_colorSpace );
const auto& other_comp = in.components();
std::ranges::transform( other_comp, m_pelComp, m_pelComp.begin(), []( auto& lhs, auto& rhs ) { return lhs + rhs; } );
return *this;
}
auto CalypPixel::operator-=( const CalypPixel& in ) -> CalypPixel&
{
assert( in.colorSpace() == m_colorSpace );
const auto& other_comp = in.components();
std::ranges::transform( other_comp, m_pelComp, m_pelComp.begin(), []( auto& lhs, auto& rhs ) { return lhs - rhs; } );
return *this;
}
auto CalypPixel::operator*=( double op ) -> CalypPixel&
{
std::ranges::transform( m_pelComp, m_pelComp.begin(), [&op]( auto& p1 ) { return p1 * op; } );
return *this;
}
auto CalypPixel::operator+( const CalypPixel& in ) const -> CalypPixel
{
assert( in.colorSpace() == m_colorSpace );
const auto& other_comp = in.components();
CalypPixel result{ m_colorSpace };
std::ranges::transform( other_comp, m_pelComp, result.components().begin(),
[]( auto& lhs, auto& rhs ) { return lhs + rhs; } );
return result;
}
auto CalypPixel::operator-( const CalypPixel& input ) const -> CalypPixel
{
assert( input.colorSpace() == m_colorSpace );
const auto& other_comp = input.components();
CalypPixel result{ m_colorSpace };
std::ranges::transform( other_comp, m_pelComp, result.components().begin(),
[]( auto& lhs, auto& rhs ) { return lhs - rhs; } );
return result;
}
auto CalypPixel::operator*( double op ) const -> CalypPixel
{
CalypPixel result{ m_colorSpace };
auto& comp = result.components();
std::ranges::transform( comp, comp.begin(), [&op]( auto& p1 ) { return p1 * op; } );
return result;
}
auto CalypPixel::operator==( const CalypPixel& other ) const -> bool
{
return colorSpace() == other.colorSpace() && std::ranges::equal( m_pelComp, other.components() );
}
auto operator<<( std::ostream& stream, const CalypPixel& pixel ) -> std::ostream&
{
// #ifdef CLP_DEBUG
// if( p.colorSpace() == CLP_COLOR_RGB || p.colorSpace() == CLP_COLOR_YUV )
// {
// os << "(" << p[0] << ", " << p[1] << ", " << p[2] << ")";
// }
// else
// {
// os << "(" << p[0] << ", " << p[1] << ", " << p[2] << ", " << p[3] << ")";
// }
// #endif
return stream;
}
auto CalypPixel::convertPixel( CalypColorSpace eOutputSpace ) const -> CalypPixel
{
if( m_colorSpace == eOutputSpace ) return *this;
int outA{ 0 };
int outB{ 0 };
int outC{ 0 };
int outD{ 0 };
if( m_colorSpace == CLP_COLOR_YUV )
{
switch( eOutputSpace )
{
case CLP_COLOR_GRAY:
outA = m_pelComp[0];
break;
case CLP_COLOR_RGBA:
outD = kMaxPixelValue;
case CLP_COLOR_RGB:
yuvToRgb( m_pelComp[0], m_pelComp[1], m_pelComp[2], outA, outB, outC );
break;
default:
break;
}
}
if( m_colorSpace == CLP_COLOR_RGB )
{
switch( eOutputSpace )
{
case CLP_COLOR_GRAY:
rgbToYuv( m_pelComp[0], m_pelComp[1], m_pelComp[2], outA, outB, outC );
case CLP_COLOR_YUV:
rgbToYuv( m_pelComp[0], m_pelComp[1], m_pelComp[2], outA, outB, outC );
break;
case CLP_COLOR_RGBA:
outD = kMaxPixelValue;
break;
default:
break;
}
}
return { eOutputSpace, static_cast<ClpPel>( outA ), static_cast<ClpPel>( outB ), static_cast<ClpPel>( outC ),
static_cast<ClpPel>( outD ) };
}