写在前面

近期好多网友私信我,问我编程该怎么学习、怎么入门。我觉得编程学习,就像写文章一样,需要积累。

如果把代码每个字符拆开,大伙都认识,但是组合在一起,就是另外一回事了。所以我的建议是,学习编程,从项目入手,从自己感兴趣的项目入手,遇到不懂的语法、算法,就去翻阅书、看视频。

如果一开始就去看生硬的语法、晦涩的算法,就像背单词一样,背到第一个单词abandon,就放弃了。

废话不多说,直接上项目,这次是一个批量去除水印的项目。

  • 环境配置:

python版本: 3.6.0

编辑器: pycharm

ps: 每一步都有代码和排版截图,方便学习

  • 代码目录结构

切记刚开始学习的时候,目录结构保持和源码一致

第一步:导入相关的python包

# encoding:utf-8
import os
from PIL import Image
import numpy as np
import imghdr

python包的作用:

os: 本项目只用到了对文件、文件夹的操作。

PIL: Python Imaging Library,是Python平台的图像处理标准库。PIL功能非常强大,API也非常简单易用。安装命令:pip install pillow

numpy: (Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。安装命令: pip install numpy

imghdr: 是一个用来检测图片类型的模块,传递给它的可以是一个文件对象,也可以是一个字节流。

第二步:参数配置类

class CONF:input_path = "input_img"    # 待处理的图片存放的位置output_path = "output_img"  # 去除水印后的图片存放位置level_black = 108    # 用于去除水印的特征值level_white = 170    # 用于去除水印的特征值is_log = True        # 是否打印日志信息

这里是个人编程的习惯,我习惯把一些配置,例如:文件路径、模型存放路径、模型参数统一放在一个类中。当然,实际项目开发的时候,是用config 文本文件存放,不会直接写在代码里,这里为了演示方便,就写在一起,也方便运行。这块代码放在代码文件的开头也方便查看和修改。

第三步:类的初始化

class DocWipe:def __init__(self, input_path, output_path, level_black, level_white, is_log):self.input_path = input_pathself.output_path = output_pathself.level_black = level_blackself.level_white = level_whiteself.is_log = is_log""" 初始化 """@classmethoddef initialize(cls, config):input_path = config.input_pathoutput_path = config.output_pathlevel_black = config.level_blacklevel_white = config.level_whiteis_log = config.is_logreturn cls(input_path, output_path, level_black, level_white, is_log)

initialize() 函数和 __init__() 函数 是对象初始化和实例化,其中包括基本参数的赋值、最后返回用户一个对象。这里作为一个类的基本操作,是属于一个通用模板,在大多数项目中,都可以这么去写。为了养成良好的编程习惯,大家可以把这个模板记下来,后续直接套用,修改部分参数就可以了。

第四步: 类的主流程函数

""" 主流程 """
def wipe_process(self,):if os.path.exists(self.input_path) and os.path.isdir(self.output_path):self.visit_dir_files(self.input_path, self.output_path, self.input_path)if self.is_log:print(u'完成!所有图片已保存至路径' + self.output_path)else:print(u'待处理的图片存放的位置 %s, 如果没有请新建目录 %s' % (self.input_path, self.input_path))print(u'去除水印后的图片存放位置 %s, 如果没有请新建目录 %s' % (self.output_path, self.output_path))

在写代码的时候,一定要抓住主线,就是代码运行的主流程。因为一个完整可靠的项目,它是有很多细枝末节考虑,很多步骤是要分模块来写。主流程就是把主心干确定好,各个模块的入口确定好。这样开发的时候,思路会比较清晰,不会被细节吸引住。这里主心干只有个函数 visit_dir_files() 的调用,但是它的外围都是一些边界条件的判定,不重要,但是没有它们程序会出现BUG。

第五步:图像处理算法

""" 图片处理 """
def img_deal(self, img_path, save_path):img = Image.open(img_path)img = self.levels_deal(img, self.level_black, self.level_white)img_res = Image.fromarray(img.astype('uint8'))if self.is_log:print(u'图片[' + img_path + u']处理完毕')img_res.save(save_path)""" 图像矩阵处理 """
def levels_deal(self, img, black, white):if white > 255:white = 255if black < 0:black = 0if black >= white:black = white - 2img_array = np.array(img, dtype=int)c_rate = -(white - black) / 255.0 * 0.05rgb_diff = np.maximum(img_array - black, 0)img_array = np.around(rgb_diff * c_rate, 0)img_array = img_array.astype(int)return img_array

在计算机看来,彩色图片是三个二维数据分别是R通道、G通道、B通道,而灰度图是一个二维数组。数值类型是uint8,简单的说,就是每个像素点是0~255的数值。去除水印的算法,其实就是对每个像素点进行运算,为了加快运算速度和代码的整洁度,使用了numpy包的矩阵运算。

这块的细节理解起来是比较有难度的,它涉及了图像处理的算法,这块可以先跳过,知道它的功能是干嘛的就行。后续有时间,再来细细琢磨。

  • 第六步: 递归访问文件
""" 创建文件夹 """
def mkdir(self, path):path = path.strip().rstrip("")is_exists = os.path.exists(path)if not is_exists:os.makedirs(path)return Trueelse:return False""" 递归访问文件/文件夹 """
def visit_dir_files(self, org_input_dir, org_output_dir, recursion_dir):single_file = Falseif os.path.isdir(recursion_dir):dir_list = os.listdir(recursion_dir)else:dir_list = [recursion_dir]single_file = Truefor i in range(0, len(dir_list)):path = os.path.join(recursion_dir, dir_list[i])if os.path.isdir(path):self.visit_dir_files(org_input_dir, org_output_dir, path)else:if imghdr.what(path):abs_output_dir = org_output_dir + recursion_dir[len(org_input_dir):]target_path = os.path.join(abs_output_dir, dir_list[i])if single_file:target_path = os.path.join(org_output_dir, os.path.basename(dir_list[i]))target_dir_name = os.path.dirname(target_path)if not os.path.exists(target_dir_name):self.mkdir(target_dir_name)self.img_deal(path, target_path)

这里也有一个难点,递归访问文件/文件夹。递归,就是自己调用自己。可以把它当成“分治法”,打个比方,如果你想解决一个很大的难题,直接计算是非常困难的,可以把它拆解成多个小问题,一个一个来解决。而递归,就是起到一个“分治”的作用。它调用的过程,就是数据结构里面的“”(先进后出)。

我当时开始学习算法的时候,递归算法也是研究了一个星期才懂它的原理。所以大家学习的时候,不要着急,先在纸上模拟调用过程,慢慢就会懂了。

第七步: 主函数入口

if __name__ == '__main__':# 对象初始化doc_wipe = DocWipe.initialize(config=CONF)# 调用主流程doc_wipe.wipe_process()

至此,加上一个main函数去调用,所有程序的入口。我们终于完成了。

最后,测试一下

用我之前写的《最近很火的文章自动生成器》,来生成随机一篇文章,并加上水印。再转成图片,作为程序的输入,运行结果:

左边有水印,右边是经过python去除了水印

注意: 仅对浅色的黑白/彩色水印有效,如WPS水印,课程水印等

最后,给一点点学习建议,不懂的时候,先弄明白它的功能以及会使用它,让代码先运行起来。等有时间就一个一个细节去攻破它,编程和写文章一样,需要慢慢积累,加油。

原文链接https://www.toutiao.com/a6810654859126112772/

html自动给图片加上水印 代码_如何给一千张图片去水印?还好我会python,100行代码轻松搞定...相关推荐

  1. bmp转换tiff c++代码_如何用Java语言将图像转换为PDF?Spire.PDF for Java轻松搞定

    对于开发人员,在日常工作中经常也会处理许多文档格式,将图像转换为PDF也是常有的事.那么,在Java语言开发中,如何将图像转换为PDF呢? Spire.PDF for Java支持将多种图像格式(例如 ...

  2. 线程导入大数据入库_大数据处理及分析该怎么做?用这款数据分析软件轻松搞定...

    ​对大数据的重视让很多企业都在纷纷寻找更好的大数据处理及分析方法?这款数据分析软件轻松搞定! 一.数据采集 虽然每天互联网都会产生大量的数据,对于企业来讲,要搜集对自己企业有用的数据才是真的大数据.首 ...

  3. 给图片加上水印php视频,如何使用PHP给图片加水印

    为了防止辛苦做出来的图片被盗用,很多照片都会加上水印,可以直接用图片工具添加水印再上传,但PHP中就可以实现给图片加水印的功能,本文章向码农们介绍 php 给图片加水印的两种方法,感兴趣的码农可以参考 ...

  4. python执行txt中代码_【技术分享】文件解压之过 Python中的代码执行

    预估稿费:200RMB 投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿 一.前言 Python中负责解压压缩文件的代码实现上并不安全,存在目录遍历漏洞,攻击者可以利用该漏洞覆盖_ ...

  5. iframe带了token不显示_不就是登录吗,能有多复杂?sa-token带你轻松搞定多地登陆、单地登录、同端互斥登录...

    前言 在java的世界里,有很多优秀的权限认证框架,如Apache Shiro.Spring Security 等等.这些框架背景强大,历史悠久,其生态也比较齐全. 但同时这些框架也并非十分完美,在前 ...

  6. js密码强度正则表达式_这20个正则表达式,能让你少写100行代码

    正则表达式,仅仅用一段非常简短的表达式语句,便能够快速实现一个非常复杂的业务逻辑.熟练地掌握正则表达式的话,能够使你的开发效率得到极大的提升. 正则表达式经常被用于字段或任意字符串的校验,如下面这段校 ...

  7. python 100行代码实现 12306 自动抢票

    基于Selenium和Chrome浏览器实现. 默认抢票类型为普通票,硬座.需求多的话可以在源码里改,我写的注释挺详细. 复制粘贴就能使用,2019年8月13日 测试可用. from selenium ...

  8. echarts 大屏可视化_看似复杂炫酷的数据可视化设计,用这波神器轻松搞定!

    数据大屏与数据可视化 数据可视化是目前对数据展示最常用的方式.数据的可视化设计有助于将复杂的数据,用最易理解的方式展示在用户的面前. 数据可视化在中后台的设计中很常见,通常主要用于分析和决策,对实时性 ...

  9. idea uml图怎么画_有了IDEA中的这款插件,流程图、类图轻松搞定,简直神器

    总有童鞋问,这个流程图图怎么绘制的,这个UML类图用什么工具做的等等,今天给大家推荐一款idea插件PlantUml,来帮助大家快速快速完成绘制. PlantUml是什么 PlantUml是一个支持快 ...

最新文章

  1. [Android] ubuntu 下不识别 Android 设备
  2. jquery插件的写法
  3. Qt学习笔记之数据库
  4. [Qt教程] 第22篇 数据库(二)编译MySQL数据库驱动
  5. 真的汉子不多,褚时健褚老算一个
  6. Mysql存储过程和存储函数
  7. Kubernetes 的自动伸缩你用对了吗?
  8. (BFS)Catch That Cow(poj3278)
  9. 网络安全与渗透测试工具集合
  10. SQL Server数据库漏洞评估了解一下
  11. python学习笔记(九)之语句1
  12. getvalue参数计数不匹配_数据人:不懂业务,分析就仅仅只是提数
  13. 关闭计算机打印共享服务,win10系统电脑打印机服务被强行关闭的解决方案
  14. IObit Uninstaller(电脑软件彻底卸载, 包含注册表) 彻底解决软件卸载不干净的问题
  15. JSP隐式对象——out对象、pageContext对象、exception对象
  16. AE开发中鹰眼的隐藏
  17. 从动物纪录片中所学所得
  18. 正则表达式叠字,过滤重复字
  19. Android安全测试用例(网络资源学习记录)
  20. L9110 - 电机控制

热门文章

  1. 工作流实战_10_flowable 流程实例的删除
  2. 第12篇:Flowable-BPMN操作流程之用户任务UserTask
  3. 一文带你初识---虚拟dom
  4. .class和getClass()的区别
  5. 切面是异步还是同步操作‘_细说JS异步发展历程
  6. 英特尔核芯显卡控制面板没有了_只认性能你就输了!英特尔第十代酷睿处理器最全解析...
  7. Python 字典推导式 - Python零基础入门教程
  8. 鸿蒙os2.0开发者beta版,鸿蒙 OS 2.0 开发者beta版针对Mate 40系列设备开放
  9. 单片机全局有必要封装_C语言开发单片机为什么大多数都采用全局变量的形式?...
  10. python初学者用什么开发环境搭建_2019-04-11 python入门学习——配置机器及搭建开发环境...