How.To.Process.Image.Infomation.Of.Rotate.And.Flip.From.Server
需求说明
客户端接收到服务器传送过来的图像数据,客户端通过对图像进行旋转和反转操作. 然后把这个旋转和反转的数据上传到服务器. 客户端在接收图像的时候, 也会下载以前的旋转和反转参数, 然后客户端根据这些数据对图形自动进行旋转和反转. 这是一个图像的矫正问题. 有大量的图像, 图像的有可能是旋转的,反转的.使用之前需要旋正和反正.
问题分析
初步分析,感觉很简单. 我只要记录旋转角度和反转状态,上传到服务器, 然后下载,根据参数做变化. 不知道你考虑到 旋转和反转的顺序问题木有?, 对于一张图像, 先旋转,后反转 和 先反转,后旋转是不同的. 还需要考虑的是, 把这2类型的参数上传到服务器, 下次, 下载的时候, 我是先用旋转参数好呢? 还是先用反转参数呢? 一些问题是存在数学规律的, 找到规律就可以迎刃而解.
旋转分为 顺时针和逆时针, 每次90度. 顺时针则+90, 逆时针则-90
反转分为 水平反转和垂直反转, 以及不反转 3种状态, 我们使用枚举类型 H_FILP,V_FLIP, NO_FLIP
对于反转, 我们得到如下规律:
- 同一方向翻转两次, 相当于没有翻转, 也就是 水平反转2次,等于没有反转. 垂直相同.
- 两次不同的翻转,相当于图像旋转180度. 也就是, 水平反转一次, 然后垂直反转一次, 等价于图像(顺时针)旋转了180度
- 当上一次没有旋转的时候, 这一次是H,就是H,是V就是V.
对于旋转, 我们得到如下规律:
- 分为顺时针(左旋), 逆时针(右旋), 每次旋转分为90度.
- 旋转的时候, 如果存在翻转, 那么翻转的方向就要改变.
伪代码实现
/** 反转状态 */
enum FLIP_STATE
{
NO_FLIP = 0, ///< 没有反转
H_FLIP, ///< 水平反转
V_FLIP ///< 垂直反转
};
/** 主要使用的变量(可以是类的成员变量) */
int m_nOldRotate; ///< Old 纪录初始旋转的参数,图像顺时针旋转0,90,180,270, 用于旋转和翻转的还原
FLIP_STATE m_oldFlipState;
int m_nRotate; ///< 记录旋转的参数,图像顺时针旋转0,90,180,270
FLIP_STATE m_flipState;
m_imShowData: 就来图像的信息类的对象
/** 水平反转事件 */
void OnHorFlip()
{
/** 反转前 */
/** 如果上一次状态是没有反转, 那么就把反转状态设置为水平反转 */
if ( NO_FLIP == m_imShowData.m_flipState ){m_imShowData.m_flipState = H_FLIP;}
/** 如果上一次状态是水平反转, 那么2次水平反转, 就是没有反转 */
else if ( H_FLIP == m_imShowData.m_flipState ){m_imShowData.m_flipState = NO_FLIP;}
/** 如果上一次状态是垂直反转, 也就是上一次是垂直,这次我要水平了, 那么两次不同方向的反转,
等价于 旋转180度, 反转设置为没有反转 */
else if ( V_FLIP == m_imShowData.m_flipState )
{
m_imShowData.m_nRotate = (m_imShowData.m_nRotate + 180) % 360;
m_imShowData.m_flipState = NO_FLIP;
}
/** 将图像水平旋转 */
OperateImage(HOR_FLIP);
}
/** 垂直反转事件 */
void OnVerFlip()
{
/** 垂直反转和水平是类似的逻辑, 请自行思考. */
if ( NO_FLIP == m_imShowData.m_flipState ){m_imShowData.m_flipState = V_FLIP;}
else if ( V_FLIP == m_imShowData.m_flipState ){m_imShowData.m_flipState = NO_FLIP;}
else if ( H_FLIP == m_imShowData.m_flipState )
{
m_imShowData.m_nRotate = (m_imShowData.m_nRotate + 180) % 360;
m_imShowData.m_flipState = NO_FLIP;
}
OperateImage(VER_FLIP);
}
/** 逆时针旋转事件 */
void OnLRotate()
{
if ( m_imShowData.m_flipState != NO_FLIP )
{
m_imShowData.m_flipState = (m_imShowData.m_flipState == H_FLIP) ? V_FLIP : H_FLIP;
}
m_imShowData.m_nRotate = (m_imShowData.m_nRotate - 90) % (-360);
OperateImage(LEFT_ROTATE);
}
/** 顺时针旋转事件 */
void OnRRotate()
{
/** 如果存在反转, 则反之方向,要发生变化 */
if ( m_imShowData.m_flipState != NO_FLIP )
{
m_imShowData.m_flipState = (m_imShowData.m_flipState == H_FLIP) ? V_FLIP : H_FLIP;
}
/** 旋转参数累加, 不做解释 */
m_imShowData.m_nRotate = (m_imShowData.m_nRotate + 90) % 360;
OperateImage(RIGHT_ROTATE);
}
/**
此函数只用于从引擎获得旋转和翻转数据以后,对原始图像进行调整使用:
获得的 旋转和翻转两个参数, 先旋转后翻转和先翻转后旋转着两种情况是不一样的.
经过测试, 应该先旋转后翻转.
*/
void SetImgRotateFlip( ImgShowData &img )
{
int nTimes = img.m_nRotate / 90;
while(nTimes > 0)
{
OperateImage(RIGHT_ROTATE);
nTimes--;
}
if( img.m_flipState == H_FLIP ){OperateImage(HOR_FLIP);}
else if( img.m_flipState == V_FLIP ){OperateImage(VER_FLIP);}
}
/** 还原很简单, 重新赋值, 调用上面的函数即可 */
void OnRevert()
{
m_imShowData.m_nRotate = m_imShowData.m_nOldRotate;
m_imShowData.m_flipState = m_imShowData.m_oldFlipState;
SetImgRotateFlip(m_imShowData);
}
/*
* 最后说一下,上传, 直接上传参数数值即可. 只是,服务器对于旋转存储的都是顺时针的数值, 也就是0,90,180,270.
* 客户端,因为存在逆时针, 所以,最后需要把逆时针的数值, 转化到顺时针, 即,逆时针的补角即可.
*/
小结
在一个坑蹲的时间长了. 这块儿地方, 才会被你改变.
How.To.Process.Image.Infomation.Of.Rotate.And.Flip.From.Server的更多相关文章
- Contents Of My Blogs
C++ How To Use Goto? Preprocessing Directive std::array std::deque std::forward_list std::map std::m ...
- Blocked Process Report
当同个对象上有互斥的锁存在时,查询需要等待很长时间,我们是否可以收到来自SQL Server提醒?答案是可以的,做法非常简单,因为SQL Server为你提供了称为Blocked Process Re ...
- android.process.acore和system进程
从源码看来,android.process.acore进程应该是一些基本功能的载入程序. android-4.3_r2.2中,它包括以下项目: 1.UserDictionaryProvider < ...
- 使用Java监控工具出现 Can't attach to the process
问题重现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ➜ jinfo -flags 3032 Attaching ...
- Server Process
1.client进行update操作后.其它是怎么协作的? Client进行update操作之后,是由Server Process真正完毕的,分以下几步: 1).须要更新的数据在Data buffer ...
- 05 Oracle process
本章提要----------------------------------------------所有的 process 都是在 PGA 内(memory)server process: 与 cli ...
- 多并发编程基础 之进程 Process
原贴 https://www.cnblogs.com/gbq-dog/p/10299663.html 1. 进程的理论知识 1.1 操作系统的背景知识 顾名思义,进程即正在执行的一个过程.进程是对正 ...
- 【oracle学习笔记02】Oracle Architecture —— Process Structure
Oracle中有三类进程: 1 User Process 2 Server Process Server Process is a program that directly interacts wi ...
- canvas/CSS实现仪表盘效果
手机上看比较虚 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <t ...
随机推荐
- 从零开始---控制台用c写俄罗斯方块游戏(2)
上回说到下移的问题,这篇就说一下刷新的问题 我们控制台输出一般都是一行一行的输出,所以,在输出屏幕的时候,我们一个画面闪到另一个画面的效果 我刚开始弄的是用system("CLS" ...
- 转:看看 Delphi XE2 为 VCL 提供的 14 种样式
http://www.linuxso.com/linuxbiancheng/8889.html 其实只提供了 个 vsf 样式文件, 还有默认的 Windows 样式, 共 种. 在空白窗体上添加 L ...
- oracle(sql)基础篇系列(五)——PLSQL、游标、存储过程、触发器
PL/SQL PL/SQL 简介 每一种数据库都有这样的一种语言,PL/SQL 是在Oracle里面的一种编程语言,在Oracle内部使用的编程语言.我们知道SQL语言是没有分支和循环的,而PL语 ...
- java复习集合类之List接口
List 为有序可重复列表 实现List接口的类主要是ArrayList 下面为ArrayList的测试代码 import java.util.ArrayList; public class demo ...
- 【专业找水题】状压dp最水题,没有之一
题目链接 现在代码能力没上升,倒是越来越会找水题了(比例题还水的裸题你值得拥有) 这网站不是针对竞赛的,所以时空限制都很宽松 然后就让我水过去了 对于每个点,包括自己的前m个元素是否取都是一种状态,所 ...
- C语言中函数声明实现的位置
在学习C语言的时候我遇到了这么个事情,因为之前先学习的C#,在C#编译器中,函数的声明位置不会影响编译的结果,但是在C语言中却发生了错误 先看一段代码: #include <stdio.h> ...
- javascript运行机制
太久没更新博客了,Javascript运行机制 Record it 1.代码块 JavaScript中的代码块是指由<script>标签分割的代码段.例如: <script type ...
- bug: 在缓存行高时,总是记录错误.
一,现象: 1.在 cell 中添加了一个 label, 并对 label 设置了 attributeText, 结果滑动的过程中,cell 的高度总是不对,多次出现下一个 cell 覆盖上一个 ce ...
- Cocopod
装了好几天,这个是比较全面的,大家可以看看帮助一下 1.新建一个项目,名称:CPTest 2.打开终端,输入"cd"+空格,然后将文件夹拖入到后面 3.回车后继续输入vim Pod ...
- [ios]新手笔记-。-UIPickerView 关于伪造循环效果和延时滚动效果
查找了网上资料,循环效果绝大部分都是增加行数来制造循环的错觉,延时滚动就是利用NSTimer间隔出发滚动事件来制造滚动效果. 代码: #import <UIKit/UIKit.h>#imp ...