爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

搜索
查看: 7519|回复: 25

[求助] 【已解决】图像旋转(转帖加求助)

[复制链接]

新浪微博达人勋

发表于 2014-9-18 09:08:15 | 显示全部楼层 |阅读模式

登录后查看更多精彩内容~

您需要 登录 才可以下载或查看,没有帐号?立即注册 新浪微博登陆

x
本帖最后由 lysx 于 2014-9-27 09:11 编辑

在这里,枫叶感谢大家的持续关注!尤其是要感谢科大的一位同学,他不是气象专业的,我也仅和他有过一面之缘。他的QQ号还是他的老师给我的。在我对这个算法的理解,程序编写过程中,他给了我很多无私的帮助。惭愧的是,我到现在也不知道他的名字。在这里,枫叶深深地致以谢意!感谢所有好人!




这里主要讨论以图象的中心为圆心旋转。旋转之后若要保持目标区域大小不变,则整幅图像变大;若要保持整幅图像的大小不变,则旋转出去的部分需要裁剪掉。


                               
登录/注册后可看大图
         旋转前的图

                               
登录/注册后可看大图
    旋转后的图

                               
登录/注册后可看大图
旋转后保持原图大小,转出的部分被裁掉
    以顺时针旋转为例来堆到旋转变换公式。如下图所示。

                               
登录/注册后可看大图

旋转前:

x0=rcosb;y0=rsinb

旋转a角度后:

x1=rcos(b-a)=rcosbcosa+rsinbsina=x0cosa+y0sina

y1=rsin(b-a)=rsinbcosa-rcosbsina=-x0sina+y0cosa
矩阵形式为

                               
登录/注册后可看大图
逆变换为


                               
登录/注册后可看大图

    上面的公式是以图像的左下角为原点旋转的。现我们要以图像的中心为原点旋转。因此需要先将坐标平移到图像中心,如下所示


                               
登录/注册后可看大图

设图象的宽为w,高为h,容易得到:


                               
登录/注册后可看大图

逆变换为


                               
登录/注册后可看大图

     现在可以分三步来完成旋转变换:

     1. 将坐标系x'o'y'平移到xoy ;  2. 在xoy坐标系下作旋转变换;  3.变换后将坐标系平移回原来位置。

     用矩阵表示就是        


                               
登录/注册后可看大图

   其中R表示旋转变换矩阵。当旋转不改变图像大小时,T 与 T' 互为逆矩阵;当旋转后图像变大时,T 与 T'不是逆矩阵关系,因为图像变大了,第一次平移和第二次平移坐标系的距离不一样。因此当图像变大时,公式应该如下:


                               
登录/注册后可看大图

    由于算法实现过程中我们需要的是逆变换的公式,因此我们只写出逆变换的表达式,如下:


                               
登录/注册后可看大图

       其中wn ,hn 表示新图像的宽和高,wo, ho 表示原图像的宽和高。

     这样,对于新图中的每一点,我们就可以根据上面逆变换公式求出对应原图中的点,得到它的灰度。如果超出原图范围,则设置为背景色。要注意的是,由于有浮点运算,计算出来点的坐标可能不是整数,采用取整处理,即找最接近的点,这样会带来一些误差(图象可能会出现锯齿)。更精确的方法是采用插值,这里暂不讨论。
    C++代码如下:

/*
* rotate.cpp
* 图像旋转变换(顺时针)
*  Created on: 2011-10-10
*      Author: LiChanghai
*/
// 以图像中心为坐标原点,旋转后不改变图像大小
// 函数返回值为指针,指向新申请的内存区域
// 因为新图像大小改变了,需要返回新图像的尺寸
// 因此形参的高度和宽度都采用指针变量
#include<string.h>
#include<stdlib.h>
#include<cmath>
#define  pi  3.1415926535
unsigned char * rotate(unsigned char *pImage, int *width, int *height, int biBitCount, float angle)
{
    //定义以图像中心为原点的坐标系下原图像和新图像的四个角点坐标
    float src_x1, src_y1, src_x2, src_y2, src_x3, src_y3, src_x4, src_y4;
    float dst_x1, dst_y1, dst_x2, dst_y2, dst_x3, dst_y3, dst_x4, dst_y4;

    //定义新图像的高度和宽度
    int wnew, hnew;

    //定义计算过程中需要的相关变量
    float sina, cosa, temp1, temp2, alpha;

    //角度转化为弧度
    alpha=pi*angle/180;

    cosa = float(cos(double(alpha)));
    sina = float(sin(double(alpha)));

    //原图像的四个角点的坐标
    src_x1 = float(-0.5*(*width)); src_y1 = float(0.5*(*height));
    src_x2 = float(0.5*(*width)); src_y2 = src_y1;
    src_x3 = src_x1; src_y3 = float(-0.5*(*height));
    src_x4 = src_x2; src_y4 = src_y3;

    //计算新图像的四个角点坐标
    dst_x1 = cosa*src_x1+sina*src_y1;
    dst_y1 = -sina*src_x1+cosa*src_y1;

    dst_x2 = cosa*src_x2+sina*src_y2;
    dst_y2 = -sina*src_x2+cosa*src_y2;

    dst_x3 = cosa*src_x3+sina*src_y3;
    dst_y3 = -sina*src_x3+cosa*src_y3;

    dst_x4 = cosa*src_x4+sina*src_y4;
    dst_y4 = -sina*src_x4+cosa*src_y4;

    //计算新图像的高度和宽度
    float t1 = fabs(dst_x4-dst_x1),  t2 = fabs(dst_x3-dst_x2);
    wnew = int(t1>t2 ? t1:t2);
    t1 = fabs(dst_y4-dst_y1),  t2 = fabs(dst_y3-dst_y2);
    hnew = int(t1>t2 ? t1:t2);

    // 计算旋转变换中的两个中间变量,便于以后计算
    temp1=float( -0.5*wnew*cosa+0.5*hnew*sina+0.5*(*width));
    temp2=float(-0.5*wnew*sina-0.5*hnew*cosa+0.5*(*height));
    //计算原图像和新图像每行像素所占的字节数(必须是4的倍数)
    int lineByte = ((*width) * biBitCount/8+3)/4*4;
    int lineByte2=(wnew * biBitCount/8+3)/4*4;

    //申请新的位图数据存储空间
    unsigned char *pImage2;
    pImage2=new unsigned char[lineByte2*hnew];

    //将新图像设置为背景色
    memset(pImage2, 0, lineByte2*hnew);

    //遍历新图像的每一个像素进行判断
    int x, y, x0, y0; // x0, y0为原图像中对应坐标
    for(y=0; y<hnew; y++)
        for(x=0; x<wnew; x++)
        {
            x0= int(x*cosa-y*sina+temp1);
            y0= int(x*sina+y*cosa+temp2);
            //如果在原图像范围内则复制像素值
            if( (x0>=0) && (x0<(*width)) && (y0>=0) && (y0<(*height)))
            {
                *(pImage2+lineByte2*y+x) = *(pImage+lineByte*y0+x0);
            }
        }

    //修改原图像的高度和宽度
    *width = wnew;
    *height = hnew;
    delete [ ] pImage; //释放原内存空间
    return  pImage2;
}


解决方案::如果需要图像裁剪,直接把计算新图像的宽度高度那几行注释掉,改为wnew=*width; hnew=*height即可。

密码修改失败请联系微信:mofangbao

新浪微博达人勋

0
早起挑战累计收入
发表于 2014-9-18 09:53:40 | 显示全部楼层
楼主是不会Fortran导致的不会还是算法不理解导致的 还是别的什么原因呢?
密码修改失败请联系微信:mofangbao

新浪微博达人勋

 成长值: 0
发表于 2014-9-18 10:02:04 | 显示全部楼层
说实话,没看懂!
1、你给了一个C的代码,是打算自己复制这个代码,转换成fortran——这个问题的话可以看懂C的语法转换就可以了;
2、只是为了解决问题的话,可以自己拿fortran写程序解决问题——呢的问题我没有看懂。

目标是想得到图像,还是得到矩形面积?
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2014-9-18 10:05:29 | 显示全部楼层
言深深 发表于 2014-9-18 10:02
说实话,没看懂!
1、你给了一个C的代码,是打算自己复制这个代码,转换成fortran——这个问题的话可以看 ...

哈哈,他这个和我前几天问的图像旋转的问题一模一样,不过我已经搞定了。
密码修改失败请联系微信:mofangbao

新浪微博达人勋

 成长值: 0
发表于 2014-9-18 10:06:13 | 显示全部楼层
lqouc 发表于 2014-9-18 10:05
哈哈,他这个和我前几天问的图像旋转的问题一模一样,不过我已经搞定了。

那就请你帮忙解决这个帖子了啊···
密码修改失败请联系微信:mofangbao

新浪微博达人勋

 楼主| 发表于 2014-9-18 10:15:58 | 显示全部楼层
mofangbao 发表于 2014-9-18 09:53
楼主是不会Fortran导致的不会还是算法不理解导致的 还是别的什么原因呢?

主要是旋转之后图像的大小发生了变化,怎么裁剪图像使得其和原始图像大小一致。即数组的大小不能改变。即使因为旋转,数组大小在中间发生了变化,那如何截取呢?还有C++的个别语句不明白。
密码修改失败请联系微信:mofangbao

新浪微博达人勋

 楼主| 发表于 2014-9-18 10:17:02 | 显示全部楼层
言深深 发表于 2014-9-18 10:02
说实话,没看懂!
1、你给了一个C的代码,是打算自己复制这个代码,转换成fortran——这个问题的话可以看 ...

我想转为fortran,实现降水矩阵的旋转。旋转后的数组大小和原始矩阵大小一致
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2014-9-18 10:17:28 | 显示全部楼层
言深深 发表于 2014-9-18 10:06
那就请你帮忙解决这个帖子了啊···

不敢不敢,我的方法太土,这种高难度的事情还要靠深深师姐啊~~
密码修改失败请联系微信:mofangbao

新浪微博达人勋

 楼主| 发表于 2014-9-18 10:18:10 | 显示全部楼层
lqouc 发表于 2014-9-18 10:05
哈哈,他这个和我前几天问的图像旋转的问题一模一样,不过我已经搞定了。

果断求助大神啊!我的邮箱是lovinf_y2011@163.com.如果您乐意把您的程序传给我,我一定感激不尽!
密码修改失败请联系微信:mofangbao

新浪微博达人勋

 成长值: 0
发表于 2014-9-18 10:27:04 | 显示全部楼层
lysx 发表于 2014-9-18 10:17
我想转为fortran,实现降水矩阵的旋转。旋转后的数组大小和原始矩阵大小一致

你这个是旋转图像还是,旋转矩阵?数组的大小又不改变又是什么意思呢?不是很懂···
密码修改失败请联系微信:mofangbao
您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

Copyright ©2011-2014 bbs.06climate.com All Rights Reserved.  Powered by Discuz! (京ICP-10201084)

本站信息均由会员发表,不代表气象家园立场,禁止在本站发表与国家法律相抵触言论

快速回复 返回顶部 返回列表