zoukankan      html  css  js  c++  java
  • Python 数据可视化 -- pillow 处理图像

    Python 图像库(Python Image Library,PIL)为 Python 提供了图像处理能力。

    PIL 官网:http://www.pythonware.com/products/pil/

    PIL 在线手册:http://www.pythonware.com/library/pil/handbook/index.htm

    pillow 是 PIL 的一个派生分支,更加活跃。

    pillow  的 github 主页:https://github.com/python-pillow/Pillow

    pillow 的文档:https://pillow.readthedocs.io/en/latest/handbook/index.html

    安装 pillow

    pip install pillow

    使用 pillow

    from PIL import Image  
    im = Image.open("hopper.ppm")

    PIL 坐标系统假定坐标(0,0)位于左上角。

    一个对图片进行过滤的例子

    import os
    from PIL import Image, ImageFilter
    
    class DemoPIL(object):
        def __init__(self, image_file=None):  #  构造器
            self.fixed_filters = [ff for ff in dir(ImageFilter) if ff.isupper()]  # dir(ImageFilter)返回ImageFilter类的属性。 isupper()是str的方法,当所有字母大写返回True
            assert image_file is not None
            assert os.path.isfile(image_file) is True  # 断言文件是否存在
            self.image_file = image_file
            self.image = Image.open(self.image_file)  # 返回一个 Image 对象实例
    
        def _make_temp_dir(self):
            from tempfile import mkdtemp
            self.ff_tempdir = mkdtemp(prefix="ff_demo_", dir="C:\Users\mail.simcere.com\Desktop")  # 创建临时路径
    
        def _get_temp_name(self, filter_name):
            name, ext = os.path.splitext(os.path.basename(self.image_file))
            newimage_file = name + "-" + filter_name + ext
            path = os.path.join(self.ff_tempdir, newimage_file)
            return path
    
        def _get_filter(self, filter_name):
            real_filter = eval("ImageFilter." + filter_name)
            return real_filter
    
        def apply_filter(self, filter_name):
            print('Applying filter:' + filter_name)
            filter_callable = self._get_filter(filter_name)
            if filter_name in self.fixed_filters:
                temp_img = self.image.filter(filter_callable)
            else:
                print("Can't apply non-fixed filter now.")
            return temp_img
    
        def run_fixed_filters_demo(self):
            self._make_temp_dir()
            for ffilter in self.fixed_filters:
                temp_img = self.apply_filter(ffilter)
                temp_img.save(self._get_temp_name(ffilter))  # 保存图像
            print("Images are in: {0}".format((self.ff_tempdir),))
    
    if __name__ == '__main__':
    #     assert len(sys.argv) == 2
        demo_image = "sunset.jpg"
        demo = DemoPIL(demo_image)  # 获取 DemoPIL 实例对象
        demo.run_fixed_filters_demo()

    处理某一特定文件夹下的所有图像文件

    指定一个目标路径,用程序读取目标路径下的所有图像,并按给定比例调整他们的大小,然后把每一个文件存储到另一个指令文件夹下。

    import os
    import sys
    from PIL import Image
    
    class Thumbnailer(object):
    
        def __init__(self, src_folder=None):
            self.src_folder = src_folder
            self.ratio = 0.3
            self.thumbnail_folder = "thumbnails"
    
        def _create_thumbnails_folder(self):
            thumb_path = os.path.join(self.src_folder, self.thumbnail_folder)
            if not os.path.isdir(thumb_path):
                os.makedirs(thumb_path)
        
        def _build_thumb_path(self, image_path):
            root = os.path.dirname(image_path)
            name, ext = os.path.splitext(os.path.basename(image_path))
            suffix = ".thumbnail"
            return os.path.join(root, self.thumbnail_folder, name + suffix + ext)
        
        def _load_files(self):
            files = set()
            for each in os.listdir(self.src_folder):
                each = os.path.abspath(self.src_folder + '/' + each)
                if os.path.isfile(each):
                    files.add(each)
            return files
        
        def _thumb_size(self, size):
            return (int(size[0]*self.ratio), int(size[1]*self.ratio))
        
        def create_thumbnails(self):
            self._create_thumbnails_folder()
            files = self._load_files()
            for each in files:
                print("Processing: " + each)
                try:
                    img = Image.open(each)  # 返回 Image对象实例
                    thumb_size = self._thumb_size(img.size)
                    resized = img.resize(thumb_size, Image.ANTIALIAS)  # 重新设置大小
                    savepath = self._build_thumb_path(each)
                    resized.save(savepath)
                except IOError as ex:
                    print("Error: " + str(ex))
    if __name__ == "__main__":
    #     assert len(sys.argv) == 2
        src_folder = "images"  # 这里提供相对路径
        if not os.path.isdir(src_folder):
            print("Error: Path '{0}' does not exists.".format((src_folder)))
            sys.exit(-1)
        thumbs = Thumbnailer(src_folder)  # 得到 Thumbnailer的实例对象
        thumbs.thumbnail_folder = "THUMBS"  # 直接修改了对象的属性,破坏了数据封装的原则
        thumbs.ratio =0.1
        thumbs.create_thumbnails()

     

     

    绘制带图像的图表

    import matplotlib.pyplot as plt
    from matplotlib._png import read_png
    from matplotlib.offsetbox import TextArea, OffsetImage, AnnotationBbox
    
    def load_data():
        import csv
        with open('pirates_temperature.csv', 'r') as f:
            reader = csv.reader(f)
            header = next(reader)
            datarows = []
            for row in reader:
                datarows.append(row)
        return header, datarows
    
    def format_data(datarows):
        years, temps, pirates = [], [], []
        for each in datarows:
            years.append(each[0])
            temps.append(each[1])
            pirates.append(each[2])
        return years, temps, pirates
    
    if __name__ == '__main__':
        fig = plt.figure(figsize=(16, 8))
        ax = plt.subplot(111)
        header, datarows = load_data()
        xlabel, ylabel, _ = header  # 将列表中的元素赋值到三个变量中
        years, temperature, pirates = format_data(datarows)
        title = 'Golbal Average Temperature vs. Number of Pirates'
        plt.plot([int(i) for i in years], [float(i) for i in temperature], lw=2)
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)
        for x in range(len(years)):
            xy = int(years[x]), float(temperature[x])
            ax.plot(int(xy[0]), float(xy[1]), "ok")
            pirate = read_png('tall-ship.png')
            zoomc = int(pirates[x])*(1/90000.0)
            imagebox = OffsetImage(pirate, zoom=zoomc)  # 
            ab = AnnotationBbox(imagebox, xy, xybox=(-200.0*zoomc, 200.0*zoomc), xycoords='data', boxcoords="offset points", pad=0.1, arrowprops=dict(arrowstyle="->", connectionstyle="angle, angleA=0, angleB=-30, rad=3"))
            ax.add_artist(ab)
            no_pirates = TextArea(pirates[x], minimumdescent=False)
            ab = AnnotationBbox(no_pirates, xy, xybox=(50.0, -25.0), xycoords = 'data', boxcoords='offset points', pad=0.3, arrowprops=dict(arrowstyle="->", connectionstyle="angle, angleA=0, angleB=-30, rad=3"))
            ax.add_artist(ab)
        plt.grid()
        plt.xlim(1800, 2020)
        plt.ylim(14, 16.5)
        plt.title(title)
        plt.show()

    pirates_temperature.csv 中的内容

    在有其它图形的图表中显示图像

    操作步骤:

    1. 加载图像

    2. 从图像矩阵中分离出RGB通道

    3. 配置图表和坐标轴(自区)

    4. 绘制通道直方图

    5. 绘制图像

    import matplotlib.pyplot as plt
    import matplotlib.image as mplimage
    import matplotlib as mpl
    import os
    
    class ImageViewer(object):
        def __init__(self, imfile):
            self._load_image(imfile)
            self._configure()
            self.figure = plt.gcf()
            t = "Image: {0}".format(os.path.basename(imfile))
            self.figure.suptitle(t, fontsize=20)
            self.shape=(3, 2)
        def _load_image(self, imfile):
            self.im = mplimage.imread(imfile)  # 读取图像 read an image from a file into an array
        def _configure(self):
            mpl.rcParams['font.size'] = 10
            mpl.rcParams['figure.autolayout'] = False
            mpl.rcParams['figure.figsize'] = (9, 6)
            mpl.rcParams['figure.subplot.top'] = 0.9
        @staticmethod
        def _get_chno(ch):
            chmap = {'R': 0, 'G': 1, 'B':2}
            return chmap.get(ch, -1)
        def show_channel(self, ch):
            bins = 256
            ec = 'none'
            chno = self._get_chno(ch)
            loc = (chno, 1)
            ax = plt.subplot2grid(self.shape, loc)
            ax.hist(self.im[:, :, chno].flatten(), bins, color=ch, ec=ec, label=ch, alpha=0.7)
            ax.set_xlim(0, 255)
            plt.setp(ax.get_xticklabels(), visible=True)
            plt.setp(ax.get_yticklabels(), visible=False)
            plt.setp(ax.get_xticklines(), visible=True)
            plt.setp(ax.get_yticklines(), visible=False)
            plt.legend()
            plt.grid(True, axis='y')
            return ax
        def show(self):
            loc = (0, 0)
            axim = plt.subplot2grid(self.shape, loc, rowspan=3)
            axim.imshow(self.im)
            plt.setp(axim.get_xticklabels(), visible=False)
            plt.setp(axim.get_yticklabels(), visible=False)
            plt.setp(axim.get_xticklines(), visible=False)
            plt.setp(axim.get_yticklines(), visible=False)
            axr = self.show_channel('R')
            axg = self.show_channel('G')
            axg = self.show_channel('B')
            plt.show()
            
    if __name__ == '__main__':
        im = 'yellow_flowers.jpg'
        try:
            iv = ImageViewer(im)
            iv.show()
        except Exception as ex:
            print(ex)

    使用 Basemap 在地图上绘制数据

    Basemap 本身不进行任何绘图工作,它只是把给定的地理坐标转换到地图投影,并把数据传给 matplotlib 进行绘图。

    basemap文档:https://matplotlib.org/basemap/api/basemap_api.html

    from mpl_toolkits.basemap import Basemap
    import matplotlib.pyplot as plt
    import numpy as np
    
    map = Basemap(projection='merc', resolution='h',area_thresh=0.1, llcrnrlon=-126.619875, llcrnrlat=31.354158, urcrnrlon=-59.647219, urcrnrlat=47.517613)
    map.drawcoastlines()
    map.drawcountries()
    map.fillcontinents(color='coral', lake_color='aqua')
    map.drawmapboundary(fill_color='aqua')
    map.drawmeridians(np.arange(0, 360, 30))
    map.drawparallels(np.arange(-90, 90, 30))
    plt.show()

    from mpl_toolkits.basemap import Basemap
    import matplotlib.pyplot as plt
    import numpy as np
    
    map = Basemap(projection='merc', resolution='h', area_thresh=100, llcrnrlon=-126.619875, llcrnrlat=25, urcrnrlon=-59.647219, urcrnrlat=55)
    shapeinfo = map.readshapefile('cities', 'cities')
    x, y = zip(*map.cities)
    city_names = []
    for each in map.cities_info:
        if each['COUNTRY'] != 'US':
            city_names.append("")
        else:
            city_names.append(each['NAME'])
    map.drawcoastlines()
    map.drawcountries()
    map.fillcontinents(color='coral', lake_color='aqua')
    map.drawmapboundary(fill_color='aqua')
    map.drawmeridians(np.arange(0, 360, 30))
    map.drawparallels(np.arange(-90, 90, 30))
    map.scatter(x, y, 25, marker='o', zorder=10)
    for city_label, city_x, city_y, in zip(city_names, x, y):
        plt.text(city_x, city_y, city_label)
    plt.title('Cities in USA')
    plt.show()

     生成验证码图像

    from PIL import Image, ImageDraw, ImageFont
    import random
    import string
    
    class SimpleCaptchaException(Exception):
        pass
    
    class SimpleCaptcha(object):
        def __init__(self, length=5, size=(200, 100), fontsize=36, random_text=None, random_bgcolor=None):
            self.size = size
            self.text = 'CAPTCHA'
            self.fontsize = fontsize
            self.bgcolor = 255
            self.length = length
            self.image = None
            if random_text:
                self.text = self._random_text()
            if not self.text:
                raise SimpleCaptchaException("field text must not be empty.")
            if not self.size:
                raise SimpleCaptchaException('Size must not be empty.')
            if not self.fontsize:
                raise SimpleCaptchaException('Font size must be defined.')
            if random_bgcolor:
                self.bgcolor = self._random_color()
        def _center_coords(self, draw, font):
            width, height = draw.textsize(self.text, font)
            xy = (self.size[0] - width)/2.0, (self.size[1] - height)/2.0
            return xy
        def _add_noise_dots(self, draw):
            size = self.image.size
            for _ in range(int(size[0]*size[1]*0.1)):
                draw.point((random.randint(0, size[0]), random.randint(0, size[1])), fill='white')
            return draw
        def _add_noise_lines(self, draw):
            size = self.image.size
            for _ in range(8):
                width = random.randint(1, 2)
                start = (0, random.randint(0, size[1]-1))
                end = (size[0], random.randint(0, size[1]-1))
                draw.line([start, end], fill="white", width=width)
            for _ in range(8):
                start = (-50, 50)
                end = (size[0] + 10, random.randint(0, size[1] + 10))
                draw.arc(start + end, 0, 360, fill='white')
            return draw
        def _random_text(self):
            letters = string.ascii_lowercase + string.ascii_uppercase
            random_text = ""
            for _ in range(self.length):
                random_text += random.choice(letters)
            return random_text
        def _random_color(self):
            r = random.randint(0, 255)
            g = random.randint(0, 255)
            b = random.randint(0, 255)
            return (r, g, b)
        def get_captcha(self, size=None, text=None, bgcolor=None):
            if text is not None:
                self.text = text
            if size is not None:
                self.size = size
            if bgcolor is not None:
                self.bgcolor = bgcolor
            self.image = Image.new('RGB', self.size, self.bgcolor)  # 
            font = ImageFont.truetype('fonts/Vera.ttf', self.fontsize)
            draw = ImageDraw.Draw(self.image)
            xy = self._center_coords(draw, font)
            draw.text(xy=xy, text=self.text, font=font)
            draw = self._add_noise_dots(draw)
            draw = self._add_noise_lines(draw)
            self.image.show()
            return self.image, self.text
        
    if __name__ == "__main__":
        sc = SimpleCaptcha(length=7, fontsize=36, random_text=True, random_bgcolor=True)
        sc.get_captcha()

  • 相关阅读:
    设计模式来替代if-else
    Cloneable接口的作用与深度克隆与浅度克隆
    IP地址分类
    MIME-TYPE
    Linux curl
    Cookie 跨域???
    冒烟测试
    @Valid、@Validated 、正则验证工具
    Node.js—第一个动态页面
    Node.js—小试牛刀-创建目录
  • 原文地址:https://www.cnblogs.com/0820LL/p/10416388.html
Copyright © 2011-2022 走看看