⼩红书去⽔印代码_如何给⼀千张图⽚去⽔印?还好我会
python,100⾏代码轻松搞定...
写在前⾯
四级缺考有什么影响近期好多⽹友私信我,问我编程该怎么学习、怎么⼊门。我觉得编程学习,就像写⽂章⼀样,需要积累。
母亲节快乐的英文如果把代码每个字符拆开,⼤伙都认识,但是组合在⼀起,就是另外⼀回事了。所以我的建议是,学习编程,从项⽬⼊⼿,从⾃⼰感兴趣
学习编程,从项⽬⼊⼿,从⾃⼰感兴趣的项⽬⼊⼿,遇到不懂的语法、算法,就去翻阅书、看视频。
怎样开饰品店的项⽬⼊⼿
如果⼀开始就去看⽣硬的语法、晦涩的算法,就像背单词⼀样,背到第⼀个单词abandon,就放弃了。
废话不多说,直接上项⽬,这次是⼀个批量去除⽔印的项⽬。
环境配置:
python版本: 3.6.0
编辑器: pycharm
ps: 每⼀步都有代码和排版截图,⽅便学习
代码⽬录结构
切记刚开始学习的时候,⽬录结构保持和源码⼀致
第⼀步:导⼊相关的python包
import os
from PIL import Image
import numpy as np
张含韵领证
import imghdr
python包的作⽤:
os: 本项⽬只⽤到了对⽂件、⽂件夹的操作。网络红人程琳
os
PIL: Python Imaging Library,是Python平台的图像处理标准库。PIL功能⾮常强⼤,API也⾮常简单易⽤。安装命令:pip install
pip install
PIL
pillow
numpy: (Numerical Python) 是 Python 语⾔的⼀个扩展程序库,⽀持⼤量的维度数组与矩阵运算,此外也针对数组运算提供⼤量的数学numpy
pip install numpy
函数库。安装命令: pip install numpy
女明星的尴尬imghdr: 是⼀个⽤来检测图⽚类型的模块,传递给它的可以是⼀个⽂件对象,也可以是⼀个字节流。
imghdr
第⼆步:参数配置类
class CONF:
input_path = "input_img"    # 待处理的图⽚存放的位置
output_path = "output_img"  # 去除⽔印后的图⽚存放位置
level_black = 108    # ⽤于去除⽔印的特征值
level_white = 170    # ⽤于去除⽔印的特征值
is_log = True        # 是否打印⽇志信息
这⾥是个⼈编程的习惯,我习惯把⼀些配置,例如:⽂件路径、模型存放路径、模型参数统⼀放在⼀个类中。当然,实际项⽬开发的时候,是⽤config ⽂本⽂件存放,不会直接写在代码⾥,这⾥为了演⽰⽅便,就写在⼀起,也⽅便运⾏。这块代码放在代码⽂件的开头也⽅便查看和修改。
第三步:类的初始化
def __init__(self, input_path, output_path, level_black, level_white, is_log):
self.input_path = input_path
self.output_path = output_path
self.level_black = level_black
self.level_white = level_white
self.is_log = is_log
""" 初始化 """
@classmethod
def initialize(cls, config):
input_path = config.input_path
output_path = config.output_path
level_black = config.level_black
level_white = config.level_white
is_log = config.is_log
return cls(input_path, output_path, level_black, level_white, is_log)
initialize() 函数和 __init__()
__init__() 函数 是对象初始化和实例化,其中包括基本参数的赋值、最后返回⽤户⼀个对象。这⾥作为⼀个类的基本initialize()
操作,是属于⼀个通⽤模板,在⼤多数项⽬中,都可以这么去写。为了养成良好的编程习惯,⼤家可以把这个模板记下来,后续直接套⽤,修改部分参数就可以了。
第四步:类的主流程函数
""" 主流程 """
def wipe_process(self,):
if ists(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。
visit_dir_files()
第五步:图像处理算法
""" 图⽚处理 """
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 = 255
if black < 0:
black = 0
if black >= white:
black = white - 2
img_array = np.array(img, dtype=int)
c_rate = -(white - black) / 255.0 * 0.05
rgb_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 = ists(path)
if not is_exists:
os.makedirs(path)
return True
else:
return False
""" 递归访问⽂件/⽂件夹 """
def visit_dir_files(self, org_input_dir, org_output_dir, recursion_dir):
single_file = False
if os.path.isdir(recursion_dir):
dir_list = os.listdir(recursion_dir)
else:
dir_list = [recursion_dir]
single_file = True
for 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 ists(target_dir_name):
self.mkdir(target_dir_name)
self.img_deal(path, target_path)
如果你想解决⼀个很⼤的
分治法”,打个⽐⽅,如果你想解决⼀个很⼤的
递归,就是⾃⼰调⽤⾃⼰。可以把它当成“分治法
这⾥也有⼀个难点,递归访问⽂件/⽂件夹。递归
难题,直接计算是⾮常困难的,可以把它拆解成多个⼩问题,⼀个⼀个来解决。⽽递归,就是起到⼀个“分治”的作⽤。它调⽤的过难题,直接计算是⾮常困难的,可以把它拆解成多个⼩问题,⼀个⼀个来解决
栈”(先进后出)。
程,就是数据结构⾥⾯的“栈