需求:将图像变形,如矩形图片变换成梯形的,图素拉伸。

解决方案:目前找到有两种。

  • 使用EmguCV,它是.Net版的OpenCV。推荐直接在VS里的Nuget中搜索EmguCV进行下载。
  • 使用第三方库FreeImageTransformation。(网上搜YLScsFreeTransform关键字)
  • 使用第三方库MagickImage。(非常厉害的魔法~)

思路:首先一张图片有四个点,给图片实体类准备一个属性,用于记录变形前和变形后的四个点XY坐标值。

public float[] ProjectTransform { get; set; }

该数组有16个float型元素,按顺序分别表示:

变形前左上角X值  变形前左上角Y值 变形后左上角X值 变形后左上角Y值
变形前右上角X值 变形前右上角Y值 变形后右上角X值 变形后右上角Y值
变形前左下角X值 变形前左下角Y值 变形后左下角X值 变形后左下角Y值
变形前右下角X值 变形前右下角Y值 变形后右下角X值 变形后右下角Y值

若使用方案一:EmguCV

  • 将Emgu的dll引入到项目中。
  • 实体类中定义一个Image属性用于保存图像,该属性是UMat类型。这是OpenCV中的类型。
  • 使用图像变形函数 CvInvoke.WarpPerspective()
private UMat image;
public UMat Image
{
get
{
if (ProjectTransform != null)
{
PointF[] corner = new PointF[4];
PointF[] trans_corner = new PointF[4];
UMat trans_img = new UMat(); // 变换前的四个角的坐标
corner[0] = new PointF(ProjectTransform[0], ProjectTransform[1]);
corner[1] = new PointF(ProjectTransform[4], ProjectTransform[5]);
corner[2] = new PointF(ProjectTransform[8], ProjectTransform[9]);
corner[3] = new PointF(ProjectTransform[12], ProjectTransform[13]); // 变换后的四个角的坐标
trans_corner[0] = new PointF(ProjectTransform[2], ProjectTransform[3]);
trans_corner[1] = new PointF(ProjectTransform[6], ProjectTransform[7]);
trans_corner[2] = new PointF(ProjectTransform[10], ProjectTransform[11]);
trans_corner[3] = new PointF(ProjectTransform[14], ProjectTransform[15]); // 变形规则
Mat transform = CvInvoke.GetPerspectiveTransform(corner, trans_corner);
// 图像变形
CvInvoke.WarpPerspective(image, trans_img, transform, new Size(image.Cols, trans_img.Rows));
return trans_img;
} return image; // 如果该图片没有ProjectTransform属性,说明该图不需要变形,直接取出来使用即可。
}
set { image = value; }
}

若使用方案二:第三方库YLScsFreeTransform

  • 从下载的项目中,通过阅读源码,只取出我们需要用到的部分,做成工具类。(下载地址
  • 使用办法如下:
private Bitmap image
public Bitmap Image
{
get
{
if (ProjectTransform != null)
{
PointF[] trans_corner = new PointF[4]; // 扭曲图像
trans_corner[0] = new PointF(ProjectTransform[2], ProjectTransform[3]); // 变换后的左上角XY
trans_corner[1] = new PointF(ProjectTransform[6], ProjectTransform[7]); // 变换后的右上角XY
trans_corner[2] = new PointF(ProjectTransform[10], ProjectTransform[11]); // 变换后的左下角XY
trans_corner[3] = new PointF(ProjectTransform[14], ProjectTransform[15]); // 变换后的右下角XY using (System.Drawing.Bitmap sourceImg = image.Bitmap)
{
YLScsDrawing.Imaging.Filters.FreeTransform filter = new YLScsDrawing.Imaging.Filters.FreeTransform();
filter.Bitmap = sourceImg;
// assign FourCorners (the four X/Y coords) of the new perspective shape
//filter.FourCorners = new System.Drawing.PointF[] { trans_corner[0], trans_corner[1], trans_corner[2], trans_corner[3] };
filter.VertexLeftTop = trans_corner[0];
filter.VertexTopRight = trans_corner[1];
filter.VertexBottomLeft = trans_corner[2];
filter.VertexRightBottom = trans_corner[3]; filter.IsBilinearInterpolation = true; // optional for higher quality
System.Drawing.Bitmap perspectiveImg = filter.Bitmap; return perspectiveImg;
}
}
return image;
}
set { image = value; }
}

若使用方案三:第三方库MagickImage

  • 在NuGet中搜MagickImage,下载最高下载量那个,导入项目中。
public Bitmap Image
{
get
{
return image;
}
set
{
if (ProjectTransform != null)
{
using (ImageMagick.MagickImage magickImage = new ImageMagick.MagickImage(value))
{
magickImage.VirtualPixelMethod = ImageMagick.VirtualPixelMethod.Transparent;
magickImage.MatteColor = new ImageMagick.MagickColor(255, 255, 255, 0);
magickImage.FilterType = ImageMagick.FilterType.Point;
magickImage.Distort(ImageMagick.DistortMethod.Perspective, ProjectTransform); image = magickImage.ToBitmap();
image.SetResolution(72, 72); // 坑点:因为WPF的默认DPI为96的问题,在图像转型Bitmap时DPI会改变,需要手动修改。
}
}
else
{
image = value;
}
}
}
  • 小问题:注意这次图片变形的过程写在了Set()中而不是Get()中,因为写Get中运行时偶尔会发生图片未经过变形处理的情况,猜想可能是因为WPF的绑定时机及先后顺序问题,写到Set中因为能确保For循环是按顺序执行的。

小结:

  • 在项目中,由于有几十张2400*1440的大图需要扭曲变形(项目需求是用2D图片的扭曲拉伸来模拟3D透视效果)。在切换图素/重新加载场景时,使用EmguCV会导致程序直接崩溃(EmguCV报错),可能是因为图像没有释放干净导致内存爆炸。所以最后改用了C#原生的YLScsFreeTransform库。运行效率感觉比OpenCV的更快。。。。最重要的是,更多的图片变形也没有导致程序崩溃。
  • 2017.5.24更新:最后选用了方案三MagickImage,是因为用YLScsFreeTransform变形的图片时等比缩放的,因此2D图像从矩形变形为梯形来模拟3D效果时,无法做到近大远小的透视效果。而用MagickImage做变形能够做到这一点!

【C#】图像的变形/变换/扭曲。用Emgu或YLScsFreeTransform(FreeImageTransformation)或MagickImage的更多相关文章

  1. PHP图像裁剪为任意大小的图像,图像不变形,不留下空白

    <?php /** * 说明:函数功能是把一个图像裁剪为任意大小的图像,图像不变形 * 参数说明:输入 需要处理图片的 文件名,生成新图片的保存文件名,生成新图片的宽,生成新图片的高 */ fu ...

  2. NOI题库 09:图像旋转翻转变换

    NOI题库开始的题,也是略水,当然也是大水,所以彼此彼此 09:图像旋转翻转变换 总时间限制: 1000ms 内存限制: 65536kB 描述 给定m行n列的图像各像素点灰度值,对其依次进行一系列操作 ...

  3. PHP图片裁剪函数(图像不变形)

    PHP图片裁剪函数(图像不变形) <? *exif_imagetype -- 判断一个图像的类型 *说明:函数功能是把一个图像裁剪为任意大小的图像,图像不变形 * 参数说明:输入 需要处理图片的 ...

  4. OpenCV-Python图像转换为PyQt图像的变形及花屏无法正常显示问题研究

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<PyQt转换显示Python-OpenCV图像实现图形化界面的视频播放>介绍了实现在OpenCV和PyQt之间转换并传递图像实现在P ...

  5. 使用Matrix控制图像或组件变换的步骤

    1.获取Matrix对象,该Matrix对象既可新创建,也可直接获取其他对象内封装的Matrix(例如Transformation对象内部) 2.调用Matrix的方法进行平移.旋转.缩放.倾斜等. ...

  6. 图像的K-L变换

    1 问题的提出 2 K-L变换的原理 3 K-L变换的计算过程 4 K-L变换的性质 5 K-L变换的深入讨论 6 K-L变换的应用

  7. (顺序表的应用5.4.2)POJ 1591 M*A*S*H(约瑟夫环问题的变形——变换步长值)

    /* * POJ_1591_2.cpp * * Created on: 2013年10月31日 * Author: Administrator */ #include <iostream> ...

  8. PS2018学习笔记(19-24节)

    19-随心所欲变换 # 本节知识点 自由变换 移动变换 旋转变换 斜切变换 变形变换 扭曲变换 透视变换 # 本节段落表 自由变换命令 变换中的移动 再次变换命令 对象缩放 旋转 斜切 变形 扭曲 透 ...

  9. 收获,不止oracle

    物理体系 体系结构图 缩放 1.Oracle由实例和数据库组成,上半部分的直角方框为实例instance,下半部分的圆角方框为数据库Database. 2.实例是由一个开辟的共享内存区SGA(Syst ...

随机推荐

  1. Intellij IDEA 设置代码着色

    从visual studio到Eclipse再到Intllij IDEA,其实每个编译器都有自己的风格,但是就美观上来说,个人觉得还是visual studio的代码着色比较美观,exlipse次之, ...

  2. ubuntu简易部署Python3编写的djangoWeb应用

    1.更新软件源 sudo apt-get update 2.安装Python3 sudo apt-get install python3 安装Python3之后建议不要修改此命令的名称,保持pytho ...

  3. 推荐系统之 BPR 算法及 Librec的BPR算法实现【1】

    [推荐系统之 BPR 算法] 1.关于BPR的论文原文: BPR: Bayesian Personalized Ranking from Implicit Feedback 2.参考1:论文快读 - ...

  4. PHP API中,MYSQL与MYSQLI的持久连接区别

    转载自:http://www.cnxct.com/some-differences-between-mysql-and-mysqli-of-persistent-connection/ 很久很久以前, ...

  5. Java虚拟机学习 - JDK可视化监控工具 ( 7 )

    1.JConsole JConsole工具在JDK/bin目录下,启动JConsole后,将自动搜索本机运行的jvm进程,不需要jps命令来查询指定.双击其中一个jvm进程即可开始监控,也可使用“远程 ...

  6. Android学习系列(12)--App列表之拖拽GridView

    根据前面文章中ListView拖拽的实现原理,我们也是很容易实现推拽GridView的,下面我就以相同步骤实现基本的GridView拖拽效果.     因为GridView不用做分组处理,代码处理起来 ...

  7. python学习笔记——正则表达式regex

    1 概述 1.1 定义 本质是由一系列字符和特殊符号组成的字串,用来表示一定规则的某一类字符串. 1.2 特点 正则表达式是一个独立的技术,其在多种编程语言中使用. 在python语言中的正则表达式模 ...

  8. Python学习笔记015——汉字编码

    1 字符串的编码(encode)格式 GB2312   GBK   GB18030  UTF-8  ASCII 其中常用的编码格式有 国标系列:GB18030(GBK(GB2312)) (window ...

  9. 【转】其他人的BUG

    在软件行业,经常看到有的公司管理让一个人修补另一个人代码里的BUG.有时候有人写了一段代码,扔出来不管了,然后公司管理让其他工程师来修复它.我想告诉你们,这种方法会很失败. 首先,让一个人修复另一个人 ...

  10. 【服务器防护】linux 如何查看防火墙是否开启

    service iptables status可以查看到iptables服务的当前状态.但是即使服务运行了,防火墙也不一定起作用,你还得看防火墙规则的设置 iptables -L在此说一下关于启动和关 ...