Files
core/ASCImageStudio3/Common/ImageTransformsCoreWrappers.h

432 lines
11 KiB
C++

#pragma once
#include "ImageTransformsCoreConstants.h"
namespace ImageStudio
{
namespace Transforms
{
namespace Core
{
namespace Wrappers
{
class MediaTransform
{
public:
MediaTransform()
{
m_pFormat = NULL;
m_pTransform = NULL;
m_bInterfacesValid = TRUE;
}
virtual ~MediaTransform()
{
Destroy();
}
BOOL ConvertToBGRA(IUnknown* pSource, IUnknown*& pResult)
{
pResult = NULL;
if (!pSource)
return FALSE;
if (!Create())
return FALSE;
MediaCore::IAVSUncompressedVideoFrame* pSourceFrame = NULL;
pSource->QueryInterface(MediaCore::IID_IAVSUncompressedVideoFrame, (void**)(&pSourceFrame));
if (NULL == pSourceFrame)
return FALSE;
// íàñòðàèâàåì ôîðìàò äëÿ êîíâåðòàöèè
LONG lWidth = 0; pSourceFrame->get_Width(&lWidth);
LONG lHeight = 0; pSourceFrame->get_Height(&lHeight);
LONG lAspectX = 0; pSourceFrame->get_AspectRatioX(&lAspectX);
LONG lAspectY = 0; pSourceFrame->get_AspectRatioY(&lAspectY);
LONG lColorSpace = 0; pSourceFrame->get_ColorSpace(&lColorSpace);
m_pFormat->put_Width(lWidth);
m_pFormat->put_Height(lHeight);
m_pFormat->put_AspectRatioX(lAspectX);
m_pFormat->put_AspectRatioY(lAspectY);
// ïðåîáðàçóåì ê BGRA32 ôîðìàòó è ñîçäàåì äóáëèêàò (âñåãäà!)
m_pTransform->SetVideoFormat(m_pFormat);
m_pTransform->TransformFrame(pSourceFrame, &pResult);
// åñëè òðàíñôîðì íå ñäåëàë äóïëèêàòà - äåëàåì åãî ðóêàìè
if (pSourceFrame == pResult) // çäåñü (pResult != NULL)
{
pResult->Release();
pResult = NULL;
pSourceFrame->CreateDuplicate(DUBLICATE_TYPE_COPY, (MediaCore::IAVSMediaData**)(&pResult));
}
// åñëè èñõîäíûé ôîðìàò áûë íå BGRA (ò.å. íå ñîäåðæàë alpha êàíàë), òî åãî íàäî çàïîëíèòü ðóêàìè çíà÷åíèåì 255
if ((lColorSpace != CSP_BGRA) && (lColorSpace != (CSP_BGRA | CSP_VFLIP)) && (NULL != pResult))
{
BYTE* pResultBuffer = NULL; ((MediaCore::IAVSMediaData*)pResult)->get_Buffer(&pResultBuffer);
if (NULL != pResultBuffer)
{
BYTE* pResultAlpha = pResultBuffer + 3;
for (int index = 4*lWidth*lHeight - 1; index >= 0; index -= 4, pResultAlpha += 4)
*pResultAlpha = 255;
}
}
pSourceFrame->Release();
return (NULL != pResult);
}
protected:
BOOL IsValid()
{
if (NULL == m_pFormat || NULL == m_pTransform)
return FALSE;
return TRUE;
}
void Destroy()
{
if (NULL != m_pFormat)
m_pFormat->Release();
if (NULL != m_pTransform)
m_pTransform->Release();
m_pTransform = NULL;
}
BOOL Create()
{
if (NULL != m_pTransform && NULL != m_pFormat)
return TRUE;
if (!m_bInterfacesValid)
return FALSE;
// ïûòàåìñÿ ñîçäàòü èíòåðôåéñ òðàíñôîðìåðà
if (NULL == m_pTransform)
{
if (S_OK != CoCreateInstance(MediaCore::CLSID_CAVSVideoFrameTransform, NULL, CLSCTX_ALL, MediaCore::IID_IAVSVideoFrameTransform, (void**)(&m_pTransform)))
{
m_pTransform = NULL;
m_bInterfacesValid = FALSE;
}
}
// ïûòàåìñÿ ñîçäàòü èíòåðôåéñ ôîðìàòà
if (NULL == m_pFormat)
{
if (S_OK != CoCreateInstance(MediaFormat::CLSID_CAVSVideoFormat, NULL, CLSCTX_ALL, MediaFormat::IID_IAVSVideoFormat, (void**)(&m_pFormat)))
{
m_pFormat = NULL;
m_bInterfacesValid = FALSE;
}
else
{
m_pFormat->SetDefaultProperties();
m_pFormat->put_ColorSpace(CSP_BGRA | CSP_VFLIP);
}
}
return IsValid();
}
protected:
MediaFormat::IAVSVideoFormat* m_pFormat; // èíòåðôåéñ, õðàíÿùèé íàñòðîéêè ôîðìàòà BGR32
MediaCore::IAVSVideoFrameTransform* m_pTransform; // èíòåðôåéñ, íåîáõîäèìûé äëÿ êîíâåðòàöèè media data â ôîðìàò BGR32
BOOL m_bInterfacesValid; // ôëàã, îáîçíà÷àþùèé - ïðîèçâîäèëàñü ëè ïîïûòêà ñîçäàòü èíòåðôåéñ òðàíñôîðìåðà èëè íåò
};
}
}
namespace NonLinearTransforms
{
//========================================================================
template<class T> void swap_arrays(T* a1, T* a2, unsigned n)
{
unsigned i;
for(i = 0; i < n; i++)
{
T tmp = *a1;
*a1++ = *a2;
*a2++ = tmp;
}
}
//========================================================================
template<unsigned Rows, unsigned Cols>
struct matrix_rot
{
static int rot(double m[Rows][Cols], unsigned row)
{
int k = int(row);
double max_val, tmp;
max_val = -1.0;
unsigned i;
for(i = row; i < Rows; i++)
{
if((tmp = fabs(m[i][row])) > max_val && tmp != 0.0)
{
max_val = tmp;
k = i;
}
}
if(m[k][row] == 0.0)
{
return -1;
}
if(k != int(row))
{
swap_arrays(m[k], m[row], Cols);
return k;
}
return 0;
}
};
//========================================================================
template<unsigned Size, unsigned RightCols>
struct simul_eq
{
static bool solve(const double left[Size][Size],
const double right[Size][RightCols],
double result[Size][RightCols])
{
unsigned i, j, k;
double a1;
double tmp[Size][Size + RightCols];
for(i = 0; i < Size; i++)
{
for(j = 0; j < Size; j++)
{
tmp[i][j] = left[i][j];
}
for(j = 0; j < RightCols; j++)
{
tmp[i][Size + j] = right[i][j];
}
}
for(k = 0; k < Size; k++)
{
if(matrix_rot<Size, Size + RightCols>::rot(tmp, k) < 0)
{
return false;
}
a1 = tmp[k][k];
for(j = k; j < Size + RightCols; j++)
{
tmp[k][j] /= a1;
}
for(i = k + 1; i < Size; i++)
{
a1 = tmp[i][k];
for (j = k; j < Size + RightCols; j++)
{
tmp[i][j] -= a1 * tmp[k][j];
}
}
}
for(k = 0; k < RightCols; k++)
{
int m;
for(m = int(Size - 1); m >= 0; m--)
{
result[m][k] = tmp[m][Size + k];
for(j = m + 1; j < Size; j++)
{
result[m][k] -= tmp[m][j] * result[j][k];
}
}
}
return true;
}
};
class PerspectiveTransformation
{
public:
//--------------------------------------------------------------------
PerspectiveTransformation() : m_valid(false) {}
PerspectiveTransformation(const double* src, const double* dst)
{
quad_to_quad(src, dst);
}
PerspectiveTransformation(double x1, double y1, double x2, double y2,
const double* quad)
{
rect_to_quad(x1, y1, x2, y2, quad);
}
PerspectiveTransformation(const double* quad,
double x1, double y1, double x2, double y2)
{
quad_to_rect(quad, x1, y1, x2, y2);
}
void quad_to_quad(const double* src, const double* dst)
{
double left[8][8];
double right[8][1];
unsigned i;
for (i = 0; i < 4; i++)
{
unsigned ix = i * 2;
unsigned iy = ix + 1;
left[ix][0] = 1.0;
left[ix][1] = src[ix];
left[ix][2] = src[iy];
left[ix][3] = 0.0;
left[ix][4] = 0.0;
left[ix][5] = 0.0;
left[ix][6] = -src[ix] * dst[ix];
left[ix][7] = -src[iy] * dst[ix];
right[ix][0] = dst[ix];
left[iy][0] = 0.0;
left[iy][1] = 0.0;
left[iy][2] = 0.0;
left[iy][3] = 1.0;
left[iy][4] = src[ix];
left[iy][5] = src[iy];
left[iy][6] = -src[ix] * dst[iy];
left[iy][7] = -src[iy] * dst[iy];
right[iy][0] = dst[iy];
}
m_valid = simul_eq<8, 1>::solve(left, right, m_mtx);
}
void rect_to_quad(double x1, double y1, double x2, double y2,
const double* quad)
{
double src[8];
src[0] = src[6] = x1;
src[2] = src[4] = x2;
src[1] = src[3] = y1;
src[5] = src[7] = y2;
quad_to_quad(src, quad);
}
void quad_to_rect(const double* quad,
double x1, double y1, double x2, double y2)
{
double dst[8];
dst[0] = dst[6] = x1;
dst[2] = dst[4] = x2;
dst[1] = dst[3] = y1;
dst[5] = dst[7] = y2;
quad_to_quad(quad, dst);
}
bool is_valid() const { return m_valid; }
void transform(double* x, double* y) const
{
double tx = *x;
double ty = *y;
double d = 1.0 / (m_mtx[6][0] * tx + m_mtx[7][0] * ty + 1.0);
*x = (m_mtx[0][0] + m_mtx[1][0] * tx + m_mtx[2][0] * ty) * d;
*y = (m_mtx[3][0] + m_mtx[4][0] * tx + m_mtx[5][0] * ty) * d;
}
private:
double m_mtx[8][1];
bool m_valid;
};
//========================================================================
class BilinearTransformation
{
public:
//--------------------------------------------------------------------
BilinearTransformation() : m_valid(false) {}
BilinearTransformation(const double* src, const double* dst)
{
quad_to_quad(src, dst);
}
BilinearTransformation(double x1, double y1, double x2, double y2,
const double* quad)
{
rect_to_quad(x1, y1, x2, y2, quad);
}
BilinearTransformation(const double* quad,
double x1, double y1, double x2, double y2)
{
quad_to_rect(quad, x1, y1, x2, y2);
}
void quad_to_quad(const double* src, const double* dst)
{
double left[4][4];
double right[4][2];
unsigned i;
for(i = 0; i < 4; i++)
{
unsigned ix = i * 2;
unsigned iy = ix + 1;
left[i][0] = 1.0;
left[i][1] = src[ix] * src[iy];
left[i][2] = src[ix];
left[i][3] = src[iy];
right[i][0] = dst[ix];
right[i][1] = dst[iy];
}
m_valid = simul_eq<4, 2>::solve(left, right, m_mtx);
}
void rect_to_quad(double x1, double y1, double x2, double y2,
const double* quad)
{
double src[8];
src[0] = src[6] = x1;
src[2] = src[4] = x2;
src[1] = src[3] = y1;
src[5] = src[7] = y2;
quad_to_quad(src, quad);
}
void quad_to_rect(const double* quad,
double x1, double y1, double x2, double y2)
{
double dst[8];
dst[0] = dst[6] = x1;
dst[2] = dst[4] = x2;
dst[1] = dst[3] = y1;
dst[5] = dst[7] = y2;
quad_to_quad(quad, dst);
}
bool is_valid() const { return m_valid; }
void transform(double* x, double* y) const
{
double tx = *x;
double ty = *y;
double xy = tx * ty;
*x = m_mtx[0][0] + m_mtx[1][0] * xy + m_mtx[2][0] * tx + m_mtx[3][0] * ty;
*y = m_mtx[0][1] + m_mtx[1][1] * xy + m_mtx[2][1] * tx + m_mtx[3][1] * ty;
}
private:
double m_mtx[4][2];
bool m_valid;
};
}
}
}