❤️【Python从入门到精通】(二十七)更进一步的了解Pillow吧!
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了❤️【Python从入门到精通】(二十七)更进一步的了解Pillow吧!相关的知识,希望对你有一定的参考价值。
参考技术A本文是接上一篇 ❤️【Python从入门到精通】(二十六)用Python的PIL库(Pillow)处理图像真的得心应手❤️ 进一步介绍Pillow库的使用, 本文将重点介绍一些高级特性:比如如何利用Pillow画图形(圆形,正方形),介绍通过Pillow库给图片添加水印;同时对上一篇文章未介绍的常用知识点进行补充说明。希望对读者朋友们有所帮助。
上一篇文章已经介绍了Image模块,但是介绍的还不够全面,例如如何从网页中读取图片没有介绍到,如何裁剪图片都没有介绍到。
读取网页中的图片的基本实现方式是:首先利用requests库读取当前图片链接的内容,接着将内容转成二进制数据,在通过open方法将该二进制数据,最后通过save方法进行保存。
读取结果是:
通过crop方法可以从图片中裁剪出一个指定大小的区域。裁取的区域范围是 (left, upper, right, lower) 比如从某个宽高都是400的图片中裁剪一个是宽高都是100的正方形区域,只需要指定裁剪区域的坐标是: (0, 0, 100, 100)
有裁剪还有一个方法就是重新设置图片大小的方法 resize,比如将前面400 400的图片 修改成 300 200,只需要调用resize方法
通过 convert方法进行图片模式的转换
前面介绍的ImageDraw库,只是介绍了利用它来向图片写入文本,其实ImageDraw模块还有一个更有用的途径,就是可以通过它来画各种图形。
首先创建一个600*600的画布。然后再画布中画出一个正方形,画直线的方法是 line方法。
ImageDraw.line(xy, fill=None, width=0, joint=None)
在xy的坐标之间画一条直线
xy--> 在两个坐标点之间画一条直线,坐标点的传入方式是[(x, y), (x, y), ...]或者[x, y, x, y, ...]
fill--> 直线的颜色
width--> 直线的宽度
画一个边框宽度为2px,颜色为蓝色的,面积为400*400的正方形。
ImageDraw.arc(xy, start, end, fill=None, width=0)
在给定的区域范围内,从开始角到结束角之间绘制一条圆弧
xy--> 定义边界框的两个点,传入的格式是[ (x0, y0), (x1, y1)] 或者 [x0, y0, x1, y1] ,其中 x1>=x0,y1>=y0
start --> 起始角度,以度为单位,从3点钟开始顺时针增加
end--> 结束角度,以度为单位
fill--> 弧线的颜色
width-->弧线的宽度
这里就是画了一个半圆,如果结束角度是360度的话则就会画一个完整的圆。
画圆通过ImageDraw.ellipse(xy, fill=None, outline=None, width=1) 方法,该方法可以画出一个给定范围的圆
xy--> 定义边界框的两个点,传入的格式是[ (x0, y0), (x1, y1)] 或者 [x0, y0, x1, y1] ,其中 x1>=x0,y1>=y0
outline--> 轮廓的颜色
fill ---> 填充颜色
width--> 轮廓的宽度
ImageDraw.chord(xy, start, end, fill=None, outline=None, width=1) 方法用来画半圆,跟arc()方法不同的是它会用直线将起始点和结束点连接起来
xy--> 定义边界框的两个点,传入的格式是[ (x0, y0), (x1, y1)] 或者 [x0, y0, x1, y1] ,其中 x1>=x0,y1>=y0
outline--> 轮廓的颜色
fill ---> 填充颜色
width--> 轮廓的宽度
ImageDraw.pieslice(xy, start, end, fill=None, outline=None, width=1)
类似于arc()方法,不过他会在端点和圆点之间画直线
xy--> 定义边界框的两个点,传入的格式是[ (x0, y0), (x1, y1)] 或者 [x0, y0, x1, y1] ,其中 x1>=x0,y1>=y0
start --> 起始角度,以度为单位,从3点钟开始顺时针增加
end--> 结束角度,以度为单位
fill--> 弧线的颜色
width-->弧线的宽度
ImageDraw.rectangle(xy, fill=None, outline=None, width=1)
xy--> 在两个坐标点之间画一条直线,坐标点的传入方式是[(x, y), (x, y), ...]或者[x, y, x, y, ...]
outline--> 轮廓的颜色
fill--> 填充的颜色
width--> 轮廓线的宽度
ImageDraw.rounded_rectangle(xy, radius=0, fill=None, outline=None, width=1) 该方法可以画一个圆角矩形
xy--> 在两个坐标点之间画一条直线,坐标点的传入方式是[(x, y), (x, y), ...]或者[x, y, x, y, ...]
radius--> 角的半径
outline--> 轮廓的颜色
fill--> 填充的颜色
width--> 轮廓线的宽度
这里有个问题,就是画好的图形如何从Image中扣出来呢?
ImageEnhance模块主要是用于设置图片的颜色对比度亮度锐度等啥的,增强图像。
原始图像
ImageFilter模块主要用于对图像进行过滤,增强边缘,模糊处理,该模块的使用方式是 im.filter(ImageFilter) 。
其中ImageFilter按照需求传入指定的过滤值。
下面一个个试下效果
4.边缘增强
ImageGrab模块主要用于对屏幕进行截图,通过grab方法进行截取,如果不传入任何参数则表示全屏幕截图,否则是截取指定区域的图像。其中box格式是:(x1,x2,y1,y2)
利用Pillow库可以轻易的对图像增加水印
首先,用PIL的Image函数读取图片
接着,新建一张图(尺寸和原图一样)
然后,在新建的图象上用PIL的ImageDraw把字给画上去,字的颜色从原图处获取。
原图
添加文字后的效果图
本文详细介绍了Pillow库的使用,希望对读者朋友们有所帮助。
Pillow官方文档
需要获取源码的小伙伴可以关注下方的公众号,回复【python】
TypeScript进阶开发——ThreeJs基础实例,从入坑到入门
前言
我们前面使用的是自己编写的ts,以及自己手动引入的jquery,由于第三方库采用的是直接引入js,没有d.ts声明文件,开发起来很累,所以一般情况下我们使用npm引入第三方的库,本文记录使用npm,typescript开发threejs3D项目,搭建基础实例,为以后开发具体业务做准备
项目结构
依旧是熟悉的SpringBoot项目,不同以往的是使用了npm管理工具来下载依赖js库,类似maven,同时为了解决typescript编译后引入npm库的路径有问题,导致浏览器报错的问题,我们采用的webpack打包工具来打包 PS:webpack依赖的文件真的是多,全都安装完后,好几百M
下面简单说一下如何初始化npm、webpack,以及下载jquery、three等js库
npm的使用
初始化
cmd先打开到项目的 threejs\\src\\main\\resources\\static 路径,使用npm init命令,回答一系列问题(当然也可以全部按照默认值),初始化成npm项目
得到node_modules目录以及package.json文件
当我们使用打包命令,会提示我们还缺少那些依赖,这时候我们按照提示去下载就可以了
有一点要注意,package.json文件的name值不能用typescript,我们改成
"name": "typescript-threejs",
脚本命令
"scripts": { "tsc": "tsc -w",//监控文件,有改动时实时编译ts "build": "webpack",//打包 "dev": "webpack -w"//监控文件,有改动时实时打包 },
webpack.config.js配置
const path = require(\'path\'); module.exports = { entry : { main : \'./src/controller/Main.ts\' }, devtool : \'inline-source-map\', mode : \'development\', module : { rules : [ { test : /\\.ts$/, use : \'ts-loader\', exclude : /node_modules/ } ] }, resolve : { extensions : [ \'.ts\', \'.js\' ] }, output : { filename : \'[name].js\', path : path.resolve(__dirname, \'./dist/\') }, plugins : [ ], optimization: { splitChunks: { chunks: "all", minSize: 30000, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: \'-\', name: true, cacheGroups: { vendors: { test: /[\\\\/]node_modules[\\\\/]/, priority: -10 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true } } } } };
使用 npm install 命令就可以下载第三方插件
下载jquery的声明文件
在node_modules目录下面j就可以看到npm下载下来的库
如何引入
使用typescript编译成js,路径不正确,浏览器报错
使用webpack编译、打包成js,路径正确
threejs
threejs,是一个JavaScript编写的WebGL第三方库。
官方文档:https://threejs.org/docs/index.html#manual/zh/introduction/Creating-a-scene
官方提供的各种例子:https://threejs.org/examples/
官方GitHub:https://github.com/mrdoob/three.js
网友克隆的官网,gitee国内镜像,网速较快:http://break_egg.gitee.io/three.js/
这里还有一个大神的博客,有比较丰富的例子可以参考:https://www.wjceo.com/
通过查阅官网文档、以及参考大量的例子进行学习,我们开始three.js之旅,采用的是npm引入的方式引入three
路径结构介绍
渲染器有三个WebGLRenderer、CSS2DRenderer、CSS3DRenderer,后面这两个是为了能够使用CSS2DObject、CSS3DObject对象作为Label,注意,使用了多个渲染器后,我们的控制器要控制的是CSS3DRenderer.domElement,控制它可以同时控制到WebGLRenderer的对象
同时,3D的渲染器DOM要加绝对定位,要不然DOM的东西显示不出来(为了统一,2D的我也加了),然后webGL的canvas也加样式,position: absolute;
然后在初始化场景时,不停的渲染,注意,有一个地方不停的渲染就可以了,多了影响性能
封装原生发射射线的方式监听对象的鼠标事件,有个地方要注意,射线只能检测到Mesh对象,Group组对象是检测不到了
更新监听事件方法:
/** * 添加cSS3DRenderer.domElement监听对象事件,利用原生射线原理,被射线检测到自身节点或者子节点则触发监听事件 */ public addEventListener(listenerObj: THREE.Object3D, even: string, callback: (object: THREE.Object3D) => void): void { let thid = this; //把具体的事件添加到对象,然后再绑定到dom,这样做的目的是为了方便后期移除 listenerObj[even] = function (event) { //阻止冒泡 event.preventDefault(); //光线投射 let raycaster = new THREE.Raycaster(); let mouse = new THREE.Vector2(); mouse.x = (event["clientX"] / thid.cSS3DRenderer.domElement.clientWidth) * 2 - 1; mouse.y = -(event["clientY"] / thid.cSS3DRenderer.domElement.clientHeight) * 2 + 1; raycaster.setFromCamera(mouse, thid.camera); // 需要被监听的对象要存储在intersectObjects中,对象本身就是一个group,所以不能直接检测射线(三维世界中点击事件需要检测射线), // 其下children里面有许多mesh,才是要被检测的目标。 let intersects; if (listenerObj.type == "Mesh") { intersects = raycaster.intersectObjects([listenerObj], false); } else { intersects = raycaster.intersectObjects(listenerObj.children, true); } if (intersects.length > 0) { // 回调函数,返回被监听对象本身 if (callback) callback(listenerObj); } }; //threejs原生事件监听 mousedown this.cSS3DRenderer.domElement.addEventListener(even, listenerObj[even], false); }
/** * 移除cSS3DRenderer.domElement监听对象事件 */ public removeEventListener(listenerObj: THREE.Object3D, even: string,): void { this.cSS3DRenderer.domElement.removeEventListener(even, listenerObj[even]); }
同时还封装了一个动画效果,按屏幕刷新率调用,每次调用++一定的值,每次回调函数返回,从0到1递增,等于1的时候结束递归调用
还有一个是镜头的巡检
其他地方就不一一介绍了,大家自己看代码
效果演示
地球模仿的是:https://wa.qq.com/xplan/earth/index.html?_wv=1
地球外部有一层漂浮的云层(大气层),效果比较逼真
云层模仿的是: http://www.sucai58.com/plus/demo.php?aid=132
云海又八千多个PlaneGeometry对象组成,推动镜头营造穿越云层的效果,作为地球场景到园区场景的过渡动画
园区是加载了官方例子的obj模型(站立的男人)以及fbx模型(跳舞的女人),跳舞的动画是模型自带的,中间那两个是普通的BoxGeometry对象(录GIF的软件录带绿色的东西效果好难看啊,我就不放上来了...)
更多效果自己运行查看
补充
1、npm install 包的时候报错
解决:给npm降级或者升级
降级 : npm install -g npm@5.4.0 //@后面是具体版本号
升级 : npm install -g npm //升级到最新版本
如果还不行就清除缓存再次安装
npm cache clean -f
2、threejs移动的时候老是报错
在three.module.js做一下小调整,非空才调用.call方法
后记
学习Three.js是因为公司的3D技术储备从原先的Twaver转用其他的库,公司大佬在考察Unity3D跟Three.js后决定用后者,Three.js是开源免费的,而Twaver跟Unity3D是要收钱的,这个例子就是我的学习Demo,主要是参考了官网的例子以及效果演示中提到的那两个列子,Demo例子大体上已经封装实现了加载OBJ、FBX、原生对象、2D、3Dlabel等,封装对象鼠标事件的监听,镜头动画封装,基本上满足业务的开发
当然还有很多不足的地方,比如事件监听是我们直接封装的检测射线方法,经过测试发现一个bug,我们已经把地球从场景中移除,但点击地球的位置依旧能触发地球的监听事件
TypeScript进阶开发——ThreeJs基础实例就暂时记录到这里,以后在补充
2019-09-05补充:
1、解决事件绑定问题,原因:虽然我们已经将对象从场景中移除,但事件监听还在,所以还是能够触发
2、眼尖的同学可以发现了,我们之前的云层过渡动画卡顿、同时还有类似“马赛克”的情况出现,卡顿是因为我们创建的云对象太多了,而马赛克是因为默认启用了深度测试,我们关掉就可以解决
我们关闭了深度测试、减少了一半的云对象,最后看一下效果(流畅了很多~)
代码开源
注:node_modules文件夹和里面的各种库文件我就不提交了,几百M太大了,大家按照上面的步骤用npm命令初始化、下载就可以了
代码已经开源、托管到我的GitHub、码云:
GitHub:https://github.com/huanzi-qch/threejs
码云:https://gitee.com/huanzi-qch/threejs
以上是关于❤️【Python从入门到精通】(二十七)更进一步的了解Pillow吧!的主要内容,如果未能解决你的问题,请参考以下文章