C++实现完整的图像平面几何变换,兼散分!!!

阿发伯 2010-10-10 04:25:37
有关图像的平面几何变换,现有的教程、计算机图书以及网上的资料上介绍理论的偏多,即使有些编程实例,也只是介绍图像几何变换的某些特例,如旋转、缩放、平移等。GDI+倒是有个Matrix类,可完整地实现图像的几何变换,可惜没法得到源码。

本人使用C++实现了一个类似GDI+ Matrix的C++几何变换类TransformMatrix。(代码较长,略,参见我的BLOG文章《实现完整的图像平面几何变换》)。
我所说的“实现完整的图像平面几何变换”,是指可以通过TransformMatrix::Multiply函数或者更直接的变换矩阵成员设置去实现“完整的”图像几何变换,除非其不能使用平面几何变换矩阵进行描述(如梯形变换我就没想到怎么实现,也许其超出了平面几何变换矩阵范畴?),或者不能进行实际的几何变换(不可逆);“实现完整的图像几何变换”的另一层含义是下面的图像变换执行函数可实现TransformMatrix所能表示的任意图像几何变换,而不必去写一个个具体的,如缩放、旋转变换函数等。

// 获取子图数据
BOOL GetSubBitmapData(CONST BitmapData *data, INT x, INT y, INT width, INT height, BitmapData *sub)
{
if (x < 0)
{
width += x;
x = 0;
}
if (x + width > (INT)data->Width)
width = (INT)data->Width - x;
if (width <= 0) return FALSE;
if (y < 0)
{
height += y;
y = 0;
}
if (y + height > (INT)data->Height)
height = (INT)data->Height - y;
if (height <= 0) return FALSE;
sub->Width = width;
sub->Height = height;
sub->Stride = data->Stride;
sub->Scan0 = (CHAR*)data->Scan0 + y * data->Stride + (x << 2);
return TRUE;
}

// 执行图像数据几何变换
VOID Transform(BitmapData *dest, INT x, INT y, CONST BitmapData *source, TransformMatrix *matrix)
{
// 复制几何变换矩阵对象
TransformMatrix m(matrix);
// 几何变换矩阵绝对增加平移量x, y
m.GetElements().dx += x;
m.GetElements().dy += y;
// 按几何变换矩阵计算并获取目标图像数据子数据
float fx, fy, fwidth, fheight;
m.GetTransformSize(source->Width, source->Height, fx, fy, fwidth, fheight);
BitmapData dst;
if (!GetSubBitmapData(dest, (INT)fx, (INT)fy,
(INT)(fwidth + 0.999999f), (INT)(fheight + 0.999999f), &dst))
return;
// 获取几何变换逆矩阵
if (!m.Invert()) return;
// 如果子图数据与目标图像原点不一致,几何变换矩阵相对增加平移量fx, fy
if (fx > 0.0f || fy > 0.0f)
{
if (fx < 0.0f) fx = 0.0f;
else if (fy < 0.0f) fy = 0.0f;
m.Translate(fx, fy);
}
// 设置子图扫描线指针及行偏移宽度
UINT *pix = (UINT*)dst.Scan0;
INT dstOffset = (dst.Stride >> 2) - dst.Width;
// 几何变换逆矩阵的平移量为与子图原点对应的源图起始坐标点
MatrixElements e = m.GetElements();
float xs = e.dx;
float ys = e.dy;
// 逐点计算并复制源图几何变换后的数据到目标子图
for (y = 0; y < (INT)dst.Height; y ++, pix += dstOffset, xs += e.m21, ys += e.m22)
{
float xs0 = xs;
float ys0 = ys;
for (x = 0; x < (INT)dst.Width; x ++, pix ++, xs0 += e.m11, ys0 += e.m12)
{
INT x0 = xs0 < 0.0f? (INT)(xs0 - 0.5f) : (INT)(xs0 + 0.5f);
INT y0 = ys0 < 0.0f? (INT)(ys0 - 0.5f) : (INT)(ys0 + 0.5f);
if (y0 >= 0 && y0 < (INT)source->Height && x0 >= 0 && x0 < (INT)source->Width)
*pix = *(UINT*)((CHAR*)source->Scan0 + y0 * source->Stride + (x0 << 2));
}
}
}

函数特点:

1、可以实现任意的图像几何变换(只要TransformMatrix能正确表达的,即变换矩阵可逆);

2、采用了GDI+ 的BitmapData结构(转换为32位ARGB像素格式),而并非任何具体的图像格式,保证了其通用性;

3、函数使用浮点数运算,但在计算像素点位置时避免了通常的浮点数乘除运算,既提高了一定的运算速度,也为以后修改为定点数运算奠定了基础;

4、函数采用临近像素插值,且没有边界像素处理代码,像素复制质量较差。

可以看出,Transform函数的着重点在于特点(1),在实际的实现代码中,可以把它作为一个框架进行扩充和修改。
下面是例子运行截图:

GDI+位图旋转45度

VCL位图缩放与剪切组合变换
...全文
488 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
阿发伯 2010-10-13
  • 打赏
  • 举报
回复
BCB人气实在太差了,结贴!
银点 2010-10-12
  • 打赏
  • 举报
回复
好东西,谢谢分享
samchoy 2010-10-12
  • 打赏
  • 举报
回复
学习学习
GoAwayZ 2010-10-12
  • 打赏
  • 举报
回复
学习~学习
CppFile 2010-10-12
  • 打赏
  • 举报
回复
接分,并mark
BORLANDSUN 2010-10-12
  • 打赏
  • 举报
回复
向您致敬!!
zzbinfo 2010-10-10
  • 打赏
  • 举报
回复
向楼主学习,呵呵
xuzhu3000 2010-10-10
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 maozefa 的回复:]
奇怪!我二楼的回帖时间是16:32:22,一楼回帖时间16:32:29,怎么沙发被他坐了呢?
[/Quote]
顶,阿发伯是图像专家,学习!!!!
paste 2010-10-10
  • 打赏
  • 举报
回复
顶顶顶,,,必须顶。。
bigfog 2010-10-10
  • 打赏
  • 举报
回复
沙发,接分.顶
lhy 2010-10-10
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 maozefa 的回复:]
奇怪!我二楼的回帖时间是16:32:22,一楼回帖时间16:32:29,怎么沙发被他坐了呢?
[/Quote]
可能是时差
阿发伯 2010-10-10
  • 打赏
  • 举报
回复
奇怪!我二楼的回帖时间是16:32:22,一楼回帖时间16:32:29,怎么沙发被他坐了呢?
|????| 2010-10-10
  • 打赏
  • 举报
回复
沙发,接分.顶
阿发伯 2010-10-10
  • 打赏
  • 举报
回复
沙发自己坐。

552

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 茶馆
社区管理员
  • 茶馆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧