1.图像裁剪、加边框、旋转(Python PIL)

1.图像裁剪、加边框、旋转(Python PIL),第1张

        日常工作中经常要用Photoshop打印一些地质图,虽然说PS有动作录制的功能,但是打印这个功能我尝试过录制动作后并未能成功运行,而且要打印的图像尺寸很多都是不同的,试了几次后就放弃了,直到后来Python学起来了,通过pywinauto库实现了这个功能,在这里就简单记录下吧。

        在写Photoshop的打印 *** 作之前,先来回顾下打印之前的图像处理工作。

        接到的地质图多为MapGIS程序导出的jpg图片,偶尔也会有Tif格式的遥感图。对这些图像进行打印很简单,基本流程是:用PS打开图像->裁剪图像四周空白边缘->为图像四周加上3cm宽白色边框(为了美观和装订的需要)->打印。那为啥用PS来打印不直接用Windows自带打印呢,应该是打印需要用到PS特定的颜色处理模式吧,经过试验,通过两种方式打出来的色彩效果确实是不同的。

        打印前图像处理的主要目标很简单:

                1、裁剪图像四周空白

                2、为图像四周加上3cm白色边框   

下面就用Python实现它们

图像处理主要用的是PIL这个库,中途由于单位电脑比较旧(4g内存Win7 32位系统,后来重装成64位了,体验就是搞这种东西必须整个64位系统),性能不太行了,也用Opencv整了下,还是感觉PIL稍微快那么一点点,不知道是不是错觉呢。

(后来发现这两步在PS录个动作也能轻松完成(→ܫ←))

一、获取所有图片路径

        有时候要打印的图片会放在好多个不同文件夹里面,要把它们遍历出来:

import os

二、读取图片并裁剪四周空白

import PIL

获得了图像尺寸后接下来就要对图像进行边缘空白的裁剪了(其实这两步不分先后顺序的):

裁剪的思路是网上搜到的,整理下就是:

    1、先把图像转成灰度模式(值变成单一的0-255以方便判断,如果要裁剪其他颜色我就不知道了,我这里只要裁掉最常见的由MapGIS导出的标准的白色边缘)。

    2、分别从四个方向扫描图像,找到四个方向各自第一个灰度值不为255(最纯粹的白色(→ܫ←))的像素,记下它的坐标(i,j)。

    3、通过四组坐标大小比较,得到图像除了四周空白区域外的坐标极值,也就得到了裁剪的区域左上(left,top)和右下坐标(right,bottom)。

    4、利用PIL.Image.crop(),完成图像的裁剪。

    5、没了,就是后来发现PIL自带这个算法,引用一下: 使用PIL裁剪图片白边

        要是用PS来做呢,‘图像-裁切-确定’就完事了。

三、给裁剪后的图像加上x厘米的白色边框

这一步主要是为了打印出来的图规范且美观。

这一步要是用PS来搞,‘图像-画布大小-设置相对的宽度和高度’ 就好了

四、判断图像是否需要旋转。

为什么要旋转这些图像呢?因为最终是要把它们用打印机打印出来,而打印机能打印的最大宽度是有限的,所以就有了这个步骤。

单位的打印机型号是惠普的HP DesignJet Z6200 60 英寸照片打印机,最大打印纸张宽度是60英寸,大约就是1524mm左右吧,除了最大尺寸外,日常还用到的纸张宽度有440、610、914、1067、1274等6、7种吧,所以出于节约打印时间和省钱的考虑,为每张图选择最合适的打印纸张宽度也是很有必要的。

判断图像是否需要旋转的思路是这样的:

    1、比较图像的宽和高,判断谁是图像的长边和短边。

    2、短边如果大于1524mm,这图按1:1就打不出来了,超过打印机最大可装入的纸张的宽度,把这个图像文件放到Oversize_path路径下,后续自己看着办。

    3、在短边小于等于1524mm的前提下,根据对图像宽高和长短边的比较,有两种需要旋转的情况:

            3.1 如果图像的宽是长边(矮胖的矩形),且宽大于1524mm,那么这图得旋转90°;

            3.2 如果图像的高是长边(瘦高的矩形),且高小于1524mm,那么这图也得旋转90°。

*printTOtkinter()是个用tkinter搞的进度显示窗口,就输出下一些文本信息而已。

五、为图像选择最合适的打印纸张尺寸

单位打印纸有438、610、914、1524等7种宽度,现在要选出最适合的一种来进行打印。

在把短边大于1524这种情况排除之后,剩下的图像情况为短边小于1524,即单位的打印机能打印出来了。

这时要判断最佳打印用纸的宽度,有两种情况需要考虑:

    1、长边>1524,改用短边来比较选择打印纸宽度。

    2、长边 ≤ 1524,用长边来比较选择打印纸宽度。

下面思路就是把要用作比较的边长放入纸张宽度列表,把列表排序后找到比这个边长大一点的那个纸张宽度。

主要的步骤就是这些,再经过一顿复制粘贴完善一下其他细节之后,最后会得到一个存放打印信息的列表,把它用txt存起来,这样后面的PS批量打印需要的信息就全部搞到手了。最后放个gif。

1图像矩

帮你计算一些属性,比如重心,面积等。

函数cv2.moments()会给你一个字典,包含所有矩值

你可以从这个里面得到有用的数据比如面积,重心等。重心可以用下面的式子得到:

2.轮廓面积

轮廓面积由函数cv2.contourArea()得到或者从矩里得到M['m00']

3.轮廓周长

可以用cv2.arcLength()函数得到。第二个参数指定形状是否是闭合的轮廓(如果传True)。或者只是一个曲线。

4.轮廓近似

这会把轮廓形状近似成别的边数少的形状,边数由我们指定的精确度决定。这是Douglas-Peucker算法的实现。

要理解这个,假设你试图找一个图像里的方块,但是由于图像里的一些问题,你得不到一个完美的方块,只能得到一个“坏方块”。现在你可以使用这个函数来近似,第二个参数叫epsilon,是从轮廓到近似轮廓的最大距离。是一个准确率参数,好的epsilon的选择可以得到正确的输出。

在下面第二个图像里,绿线显示了epsilon = 10% of arc length 的近似曲线。第三个图像显示了epsilon = 1% of the arc length。第三个参数指定曲线是否闭合。

5.凸形外壳

凸形外壳和轮廓近似类似,但是还不一样(某些情况下两个甚至提供了同样的结果)。这儿,cv2.convexHull()函数检查凸面曲线缺陷并修复它。一般来说,凸面曲线总是外凸的,至少是平的,如果它内凹了,这就叫凸面缺陷。比如下面这张图,红线显示了手的凸形外壳。双向箭头显示了凸面缺陷,是轮廓外壳的最大偏差。

参数详情:

·points 是我们传入的轮廓

·hull 是输出,一般我们不用传

·clockwise: 方向标示,如果是True,输出凸形外壳是顺时针方向的。否则,是逆时针的。

·returnPoints:默认是True。然后会返回外壳的点的坐标。如果为False,它会返回轮廓对应外壳点的索引。

所以要获得凸形外壳,下面

但是如果你想找到凸面缺陷,你需要传入returnPoints = False。我们拿上面的矩形图形来说,首先我找到他的轮廓cnt,现在用returnPoints = True来找他的凸形外壳,我得到下面的值:[[[234 202]], [[51 202]], [51 79]], [[234 79]]]  是四个角的点。如果你用returnPoints = False,我会得到下面的结果:[[129], [67], [0], [142]].  这是轮廓里对应点的索引,比如cnt[129] = [234, 202]],这和前面结果一样。

6.检查凸面

有一个函数用来检查是否曲线是凸面, cv2.isContourConvex().它返回True或False。

7.边界矩形

有两种边界矩形

7.a.正边界矩形

这个矩形不考虑对象的旋转,所以边界矩形的面积不是最小的,函数是cv2.boundingRect()。

假设矩形左上角的坐标是(x,y), (w, h)是它的宽和高

7.b.渲染矩形

这个边界矩形是用最小面积画出来的,所以要考虑旋转。函数是cv2.minAreaRect()。它返回一个Box2D结构,包含了(左上角(x,y),(width, height),旋转角度)。但是要画这个矩形我们需要4个角。这四个角用函数cv2.boxPoints()得到

8.最小闭包圆

我们找一个目标的外接圆可以用函数cv2.minEnclosingCircle().这个圆用最小面积完全包围目标。

9.椭圆

用一个椭圆来匹配目标。它返回一个旋转了的矩形的内接椭圆

10. 直线

类似的我们可以匹配一根直线,下面的图像包含一系列的白色点,我们可以给它一条近似的直线。

END


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/bake/11729238.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-18
下一篇 2023-05-18

发表评论

登录后才能评论

评论列表(0条)

保存