python实现图片加水印

为了防止博客被爬,本站的所有文章的图片都添加水印。前几天刚刚学习完python,拿来练练手,确实有很多不熟悉的类库和代码,权当试试水了。。

#! /usr/bin/python
# coding:utf-8 
import os
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import random

def Watermark(fname, text):
    # 设置字体
    font = ImageFont.truetype("STLITI.TTF", 25)  # 不同的电脑可能不存在这里的字体,导致最后没有输出结果;如果你的电脑上没有这几种字体,请自行修改

    # 实例化图片对象
    imageFile = fname
    img = Image.open(imageFile).convert('RGBA')
    text_overlay=Image.new("RGBA",img.size,(255,255,255,0))
    draw = ImageDraw.Draw(text_overlay)

    t=max(text)
    t_len=len(t)

    for i in range(0, img.size[0], t_len*20+100):
        for j in range(0, img.size[1], t_len*20):
            draw.text((i, j), random.choice(text), font=font, fill=(0, 0, 0, 50))

    text_overlay = text_overlay.rotate(45)
    image_with_text = Image.alpha_composite(img, text_overlay)
    # 另存图片
    image_with_text.save("{}_marked.png".format(fname.split(".")[0]))



def drawText(path,text):
    if not os.path.exists(path):
        print("没有这个路径:",path)
    fileList= [os.path.join(fpathe,f) for fpathe,dirs,fs in os.walk(path) for f in fs if f.split(".")[1] in ["png","jpg"] and not f.split(".")[0][-6:]=="marked"]
    for img in fileList:
        Watermark(img,text)


if __name__ == '__main__':

    path="root"
    drawText(path,["text1","text2"])

本站的图片加水印对比效果:
tensorflow{:height=”600px” width=”600px”}
tensorflow{:height=”600px” width=”600px”}

阅读更多

Python的学习笔记--画图

海龟绘图

海龟绘图画图比较简单,主要使用python的turtle模块, 就是通过编程指挥一个小海龟在屏幕上前进和左转右转。

forward: 向前走,可以指定一个距离
left:左转,指定一个角度
right:右转,指定一个角度
circle:画圆
reset:重置

根据上面的说明我们可以简单的绘制一个五角星:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import turtle
t = turtle.Pen()
for x in range(5):
t.forward(100)
t.right(145)
turtle.done()
```

![海龟绘图](/img/assets/42/01_marked.png)

绘制螺旋阵:

``` python
import turtle
import time
turtle.pensize(2)
turtle.bgcolor("black")
turtle.tracer(False)
turtle.color("white")
for x in range(400):
turtle.forward(2*x)
turtle.left(60)
turtle.tracer(True)
turtle.done()

螺旋阵
更多的方法的说明可以看官方教程

阅读更多

Python的学习笔记--枚举

枚举

python中,枚举使用Enum模块。 具体使用如下:

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
26
27

from enum import Enum

Week=Enum("Week",('Mon','Tue','Wen','Thu','Fri','Sta','Sun'))

```

在枚举中可以自动为下面的变量赋值,我们可以使用迭代把数据显示出来:

``` python
from enum import Enum
Week=Enum("Week",('Mon','Tue','Wen','Thu','Fri','Sta','Sun'))

for k, v in Week.__members__.items():
print(k, ':', v, ',', v.value)
```

打印结果:

``` cte
Mon : Week.Mon , 1
Tue : Week.Tue , 2
Wen : Week.Wen , 3
Thu : Week.Thu , 4
Fri : Week.Fri , 5
Sta : Week.Sta , 6
Sun : Week.Sun , 7

如果像自定义枚举的值,可以使用继承的方法,自定义一个枚举:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from enum import Enum, unique

class Week(Enum):
Sun = 0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6

for k, v in Week.__members__.items():
print(k, ':', v, ',', v.value)

打印结果:

1
2
3
4
5
6
7
Sun : Week.Sun , 0
Mon : Week.Mon , 1
Tue : Week.Tue , 2
Wed : Week.Wed , 3
Thu : Week.Thu , 4
Fri : Week.Fri , 5
Sat : Week.Sat , 6

可以使用@unique装饰器来保证值的唯一。

1
2
3
4
5
6
7
8
9
10
11
12
from enum import Enum, unique

@unique
class Week(Enum):
Sun = 0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
Sat = 6

上面的代码会报错:TypeError: Attempted to reuse key: 'Sat'

阅读更多

Python的学习笔记--面向对象编程

模块


随着项目增大,功能越来越复杂,为了提高代码的复用性和降低功能间的耦合,提出了模块的概念。

python中有很多的模块,使用时候直接用import导入对应的包就可以使用。

1
import sys

这样就导入了一个sys模块,我们可以在代码中直接使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import sys
def func():
print (sys.argv)

func()
```

打印结果是当前的文件所在的路径。

解释`sys`的作用:
`sys.argv` 用list来存储命令行传过来的参数。第一个参数是.py文件名称,例如:

`python3 xxx.py` 运行结果就是`['xxxx.py']`

`python3 xxxx.py abc` 运行结果:`['xxxx.py', 'abc']`。

在python的模块中,有一个特殊的变量`__name__`,这个变量的作用就是如果当前运行的是当前文件,这个变量的值就是`__main__`,所以如果想对一个模块使用测试方法,可以利用这个变量:

``` python
if __name__=="__main__":
func()

为了防止模块的命名有冲突,python 又引入了的概念,包其实可以简单的认为就是一个文件的路径,例如有如下目录结构:

1
2
3
4
5
6
A
|- abc.py

B
|- abc.py

上面的两个abc.py没有冲突。

阅读更多

Python的学习笔记--装饰器

python的函数也属于一个对象,可以有一个变量来代替,例如前面说过的一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
f=abs
print(f(-10))
```

如果我们在不改变原来函数的前提下,想扩展一个函数的功能。可以重新定义一个函数,把要原函数作为参数传递给`增强函数`,在调用函数前执行一些动作。

```python
def revert(a):
return abs(a)

def new_func(func):
print("do something")
return func

f=new_func(revert)
print(f(-10))

打印结果是:

1
2
do something
10

对于上面的代码,new_func就是装饰器,可以使用@对其进行简化:

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
26
27
28
29
30
31
32
33
def new_func(func):
print("do something")
return func

@new_func
def revert(a):
return abs(a)

print(revert(-10))

```

这样可以省去一个变量的定义,也维持了原来的方法名称。


上面的装饰器有点过于简单,因为我们只能在`return` 语句前增加内容,想在方法后面增加一个确不行,为了能够实现更强大的装饰器,我们可以对其做修改,再增加一层函数:

``` python
def new_func(func):
def inner(a):
print("do something")
res=func(a)
print("something is done")
return res
return inner

@new_func
def revert(a):
print ("processing")
return abs(a)

print(revert(-10))

打印结果:

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
do something
processing
something is done
10
```

上面这个装饰器基本满足了我们的需求,但同样还有一个问题,上面的装饰器,只能传递一个参数,所以还是不够一般性。

我们可以使用函数的默认值的方法来解决这个问题,官方给的是`*args 和 **kwargs`(tuple和dict类型),修改如下:

``` python
def new_func(func):
def inner(*args,**kw):
print("do something")
res=func(*args,**kw)
print("something is done")
return res
return inner
@new_func
def revert(a):
print ("processing")
return abs(a)

print(revert(-10))

我们再增加一个方法:

1
2
3
4
5
6
@new_func
def add(x,y):
print ("processing")
return x+y;
print(add(1,2))

阅读更多

Python的学习笔记--函数式编程

函数式编程 主要思想是把运算过程尽量写成一系列嵌套的函数调用,不严谨的说:可以把函数的引用传递给变量。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> abs(-10)
10
>>> f=abs
>>> f(-10)
10
```
`f`就引用了abs函数的地址。

1. 可以把函数当成参数传递给另一个函数:

```python
def add(x,y,f):
return f(x)+f(y)
print(add(-1,2,abs))
  1. 函数也可以当成返回值:

    1
    2
    3
    def getMethod():
    return abs
    print(getMethod()(-1))

    打印结果是:1

  2. python也支持lambda表达式

    1
    2
    f=lambda x:x+x
    print(f(10))

    打印结果是:10

  3. 可以固定一个函数的默认值,返回一个新函数

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
         import functools
    def add(x="2"):
    print(x)
    add()
    add1=functools.partial(add, x="5")
    add1()
    ```
    打印结果:`2 5`

    我们使用`functools.partial`方法把`add`的默认值修改成一个新的函数`add1`


    #### 常用的几个函数

    - map和reduce使用

    `map`函数的格式可以大致的表示为:`map(func,[])`,其功能就是把数组的每一个元素代入到`func`函数中,具体的实现功能如下:

    `list(map(abs,[-1,3,4,-6]))`,打印结果是:[1,3,4,5]

    我们可以根据其定义编写对应的功能:

    ```python
    def map1(func,arr):
    l=[]
    for x in arr:
    yield func(x)

    print(map1(abs,[1,-3,-4,6]))
    ```

    `reduce`是一个累计的函数,把上次计算的结果,当成下次运行的一个参数:`s1=f(x,y);s2=f(s1,z);`

    ``` python
    def add(x,y):
    return x+y
    print(reduce(add,[1,-3,-4,6]))
    ```
    计算结果:`1-3-4+6=0`

    用python代码来表示`reduce`

    ``` python
    def reduce1(func,arr):
    s=0
    for x in arr:
    s=func(s,x)
    return s;

阅读更多

Python的学习笔记--高级特性

数组的切片

定义一个数组

1
arr=list(range(100))
  1. 数组取前3个元素 arr[0:3],0可以省略,arr[:3],打印结果:[0,1,2]

  2. 数组取后面三个元素: arr[-3:0],也可写为:arr[-3:],打印结果:[97,98,99]

  3. 数组取后面三个元素: arr[97:],是跳过前97个数字,打印结果:[97,98,99]
  4. 可以指定取值的间隔 arr[:10:2],打印结果:[0, 2, 4, 6, 8]
    如果在全部范围内查询,可以省略查询的个数,arr[::2]这样打印出来所有的偶数。

  5. 切片的方法同样适用于tuple

  6. 字符串可以看成是字符的数组,可以使用,"ABCDEFG"[:3] 输出结果ABC

迭代循环

  1. list的循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
         arr=list(range(10))
    for a in arr:
    print(a)
    ```

    2. `dict`循环

    ```python
    dict={"a":1,"b":2,"c":3}
    for a in dict:
    print(a)
    ```

    ```python
    dict={"a":1,"b":2,"c":3}
    for x,y in dict.items():
    print(x,y)
    ```

    ``` cte
    a 1
    b 2
    c 3

  2. 字符串循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
         for a in "ABCD": 
    print(a)

    ```
    4. 多个变量
    ```python
    for x, y in [(1, 1), (2, 4), (3, 9)]:
    print(x, y)

    ```
    打印结果:
    ``` cte
    1 1
    2 4
    3 9
  3. 带索引的循环写法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    for i, value in enumerate(['A', 'B', 'C']):
    print(i, value)

    ```
    打印结果:

    ```cte
    0 A
    1 B
    2 C
  4. 判断能否被迭代

    1
    2
    3
    from collections import Iterable
    isinstance('abc', Iterable)

列表生成式

列表生成式可以更简单的把生成一个list或者tuple.

定义一个100的数组,arr=list(range(100))

  1. 定义一个100偶数的数组

    1
    2
    3
    4
    arr=[2 * x for x in list(range(100))]

    或者arr=[x for x in list(range(200)) if x%2==0]

    打印结果:[0,2,4...198]

  2. 定义两个循环生成一个组合

    1
    str=[a+b for a in "ABC"  for b in "XYZ"]  

    打印结果:['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

  3. 使用多个变量

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
         dict = {'a': 'A', 'b': 'B', 'c': 'C' }
    dic=[k + '=' + v for k, v in dict.items()]
    print(dic)
    ```

    打印结果:`['a=A', 'b=B', 'c=C']`

    4. 使用函数

    ``` python
    arr=[x.upper() for x in "abc"]
    print(arr)

    ```

    打印结果:`['A', 'B', 'C']`

    获得当前路径,可以用一句代码
    ```python
    import os
    fs=[d for d in os.listdir('.')]
    print(fs)
    ```


    5. 表达式可以赋值给一个变量,实现延迟加载

    ``` python
    g = (2 * x for x in range(10))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))

    打印结果:0,2,4,6,8

    也可以使用循环打印:

    1
    2
    3
    g = (2 * x for x in range(10))
    for x in g:
    print(x)
阅读更多

Python的学习笔记--函数

函数的定义


python使用def来定义

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
26
27
def print_str(x):
print (x)
```
调用`print_str("12")` 打印`12`


#### 默认参数
----------------------------

`python`支持默认参数。

```python
def print_str(x,y="end"):
print (x,y)
```

调用`print_str("12")`,不传递y参数 打印`12 end`
调用`print_str("12","continue")` 打印`12 continue`

如果是多个默认参数,可以根据参数的名称来指定参数。

``` python
def print_str(x,y="y",z="z"):
print ("x:",x)
print ("y:",y)
print ("z:",z)

当调用print_str(1,2),打印结果:

1
2
3
4
5
6
7
8
9
10
x: 1
y: 2
z: z
```

当调用`print_str(1,z=2)`,打印结果:
``` cte
x: 1
y: y
z: 2

使用默认参数需要注意一个问题:默认定义的时候,默认参数值已近计算出来,如果是一个默认参数是一个引用,则会发生改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def add_dict(arr=[]):
arr.append("end")
print (arr)
add_dict()
add_dict()
add_dict()
```

打印结果如下:

```cte
['none']
['none', 'none']
['none', 'none', 'none']

所以,如果使用可变的引用变量,则注意这种形式。可以使用None来代替:

1
2
3
4
5
6
def add_dict(arr=None):
if arr is None:
arr=[]

arr.append("end")
print (arr)

可变参数

阅读更多

Python的学习笔记---dict和set

dict类型的使用

python有一个dict类型,存储格式是key:value的形式,在其他语言有的成为mapDictionary.

1
2
3
4
5
6
7
8
9
10
11
>>> dict={"a":1,"b":3}
>>> dict["a"]
1
```
由于`dict`是根据key查询数据,所以查询的效率比`list`要高出不少。

取值的时候,key如果不存在则会报异常。所以为了更安全的使用`dict`可以使用前判断下:

``` ptyhon
>>> "a" in dict
True

或者可以使用get函数,如果不存在,则返回None数据,也可以指定默认值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> dict.get("c")
>>> dict.get("c",1)
1
>>>
```

> 1. dict的key必须是不可变对象
> 2. dict的内部顺序和存储的先后顺序没有关系
> 3. 查找和插入的速度极快,不会随着key的增加而变慢
> 4. 需要占用大量的内存,内存浪费多。


`dict`可以使用`pop`方法对数据进行删除:

```python
>>> dict.pop("b")
3
>>> dict
{'a': 1}

set类型

set类型与list相似,是一种不会有重复数据的数组:

1
2
3
4
5
6
>>> list=[1,2,1,2,3,3,4,5,1,1,1,1,5,6]
>>> list
[1, 2, 1, 2, 3, 3, 4, 5, 1, 1, 1, 1, 5, 6]
>>> set(list)
{1, 2, 3, 4, 5, 6}
>>>

set可以使用add()方法增加数据,如果增加重复数据,但不会有效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> list=[1,2,1,2,3,3,4,5,1,1,1,1,5,6]
>>> aset=set(list)
>>> aset
{1, 2, 3, 4, 5, 6}
>>> aset.add(7)
>>> aset
{1, 2, 3, 4, 5, 6, 7}
>>> aset.add(7)
>>> aset
{1, 2, 3, 4, 5, 6, 7}
```

使用`remove`移除数据:

```Python
>>> aset.remove(1)
>>> aset
{2, 3, 4, 5, 6, 7}
阅读更多

Python的学习笔记---list和tuple

今天学习了python的list和tuple的使用,python中的数组类型的结构比其他语言更为灵活,下面我们说说他们的用法:

list使用

  1. 定义一个list

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    >>> arr=[1,2,3,4,5,6]
    >>> arr
    [1, 2, 3, 4, 5, 6]
    ```
    `arr`就是定义的数组,使用索引来获得数组里面的数据如:`arr[0],arr[1]`等等,在python数组有一个特殊的用法,使用`-1,-2`可以取倒数第一或第二的值。

    ``` python
    >>> arr[0]
    1
    >>> arr[-1]
    6
    ```

    如果超出界限,会抛出异常:

    ``` ex
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    IndexError: list index out of range
    ```

    由于python是弱类型的语言,所以数组里面可以存储不同类型的数据:

    ```python
    >>> arr=[1,2,"hello",[1,2,34]]
    >>> arr
    [1, 2, 'hello', [1, 2, 34]]
    ```
    如果想拿到`34`这个值,可以类似二维数组那样`arr[3][2]`

    可以使用`range`函数快速定义个有序的数组:

    ```python
    >>> list(range(10))
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>>

    range的具体的使用方法range(start, stop[, step])
    range(1,10,2)代表的从1-10每次长度的2

  1. 数组的相关的函数

    • len 获得数组的长度

      1
      2
      >>> len(arr)
      4
    • append 增加一个元素

      1
      2
      3
      4
      >>> arr.append("1111")
      >>> arr
      [1, 2, 'hello', [1, 2, 34], '1111']
      >>>
    • insert插入数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
           >>> arr.insert(1,213)
      >>> arr
      [1, 213, 2, 'hello', [1, 2, 34], '1111']
      ```

      `insert(1,213)`代表在`1`位置,插入一个`213`的数字


      - `pop`删除元素

      `pop`是`python`中删除元素的方法,`arr.pop()`默认删除最后一个元素,`arr.pop(i)`代表可以删除指定位置的元素:

      ```python
      >>> arr.pop()
      '1111'
      >>> arr
      [1, 213, 2, 'hello', [1, 2, 34]]
      >>>
      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
      26
                >>> arr.pop(1)
      213
      >>> arr
      [1, 2, 'hello', [1, 2, 34]]
      ```

      #### tuple的使用

      `tuple`是一个有序的数组,和`list`类似,`tuple`的特点是定义后不能在被修改,这样可以让代码中的数据更加安全。

      定义`tuple`使用`()`,例如定义一个`tuple`如下:

      ```python
      >>> tup=(1,2,3)
      >>> tup
      (1, 2, 3)
      ```

      由于`tuple`不可修改,所以不能使用`append`,`insert`等修改元祖的方法。

      如果定义一个只有一个元素的`tuple`:

      ```python
      >>> tup=(1)
      >>> tup
      1

      这样我们发现,tup不是一个元祖,而是一个数字。原来是只用一个元素的时候,tuple中的()与数学运算中的括号冲突了,所以当定义只有一个元素的tuple的时候,需要在最后加一个,,方法如下:

1
2
3
>>> tup=(1,)
>>> tup
(1,)

如果在tuple中定义一个数组,如果改变数组的值,tuple中的值也会发生改变:

1
2
3
4
5
>>> tup=(1,[1,2])
>>> tup[1][0]="a"
>>> tup[1][1]="b"
>>> tup
(1, ['a', 'b'])
阅读更多