Source code for improc.blkptcs.blocks

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2015-09-31 21:38:26
# @Author  : Zhi Liu (zhiliu.mind@gmail.com)
# @Link    : http://iridescent.ink
# @Version : $1.1$


from __future__ import absolute_import
import os
import math
import random
import numpy as np
# from scipy.misc import imread,
from ..io.image import imreadadv, imwriteadv
import matplotlib.pyplot as plt
from ..transform.preprocessing import scalearr, imgdtype
from ..utils.log import *


r"""
Functions to split some images into blocks.

Functions can split different size images randomly or orderly(column-wise or
row-wise):

.. autosummary::
    :nosignatures:

    imgs2blks
    blks2imgs

"""

# np.random.seed(2016)


def _padhwc(imgsize, blksize):
    # computes pad h w c
    hpad = np.mod(imgsize[0], blksize[0])
    wpad = np.mod(imgsize[1], blksize[1])
    cpad = np.mod(imgsize[2], blksize[2])
    if hpad > 0:
        hpad = blksize[0] - hpad
    if wpad > 0:
        wpad = blksize[1] - wpad
    if cpad > 0:
        cpad = blksize[2] - cpad
    return hpad, wpad, cpad


[docs]def padimgs(imgs, pad_width, mode): pimgsorig = np.pad(imgs, pad_width, mode) pimgsize = pimgsorig.shape if np.ndim(imgs) == 3: pimgs = np.zeros( (pimgsize[0], pimgsize[1], pimgsize[2], 1), imgs.dtype) pimgs[:, :, :, 0] = pimgsorig return pimgs else: return pimgsorig
# splits padded images into blocks
[docs]def pimgs2blks(pimgs, blksize): """ blks: bH-bW-bC-bN, img1_blk1_bc1, img1_blk1_bc2, img1_blk1_bc3, img1_blk2_bc1, img1_blk2_bc2, img1_blk2_bc3, ... """ pH, pW, pC, pN = pimgs.shape # (H+0)-by-(W+0)-by-Channels-by-numImages mnBlock = np.array([pH, pW, pC]) / np.array(blksize) numBlks1 = np.int(np.prod(mnBlock)) blks = np.zeros( [blksize[0], blksize[1], blksize[2], pN * numBlks1], pimgs.dtype) cnt = 0 for n in range(0, pN): for i in range(0, pH, blksize[0]): for j in range(0, pW, blksize[1]): for k in range(0, pC, blksize[2]): blks[:, :, :, cnt] = pimgs[ i:blksize[0] + i, j:blksize[1] + j, k:blksize[2] + k, n] # if cnt < 6: # plt.figure(cnt) # plt.imshow(blks[:,:,:,cnt]) cnt = cnt + 1 return blks
[docs]def imgs2blks(imgs, blksize=[8, 8, 3], padmode='symmetric'): r""" blks, imgsShape = imgs2blks(imgs, blksize) trys to split the imgs(an H-W-C -N numpy ndarray, or list of images filepathes) into image blocks(an bH-bW- bC-bN ndarray) orderly; imgsShape contains each image's size in imgs for fighting back to images. Trys to split some images into blocks orderly (1.channel-wisely, 2.colum- wisely, 3.row-wisely). Parameters ---------- imgs : {array_like, or list of image pathes}. Images to be splited, a H-W-C-N numpy ndarray, or a list of image pathes with diffrent image shapes. blksize : {int tuple, list or None, optional} Specifies the each block size (rows, cols, channel) that you want to split. If not given, blksize=[8, 8, 3]. padmode : {str or None, optional} Padding mode when an image can't be split fully. 'symmetric' or 'edge' can be choosen, see np.pad for more option. The Channel will also be pad if it is not enough, e.g., for an H-W-1(gray) image, if you want to get blksize=[8,8,3]. Returns ------- blks : {ndarray} A bH-bW-bC-bN numpy ndarray, (bH, bW, bC) == blksize. imgsshape : {tuple} A tuple contains the shape of each image in imgs. Even if all images have the same size, imgsshape will still contain each image size like ((H, W, C), (H, W, C)). See Also -------- imgs2ptcs, imgs2blks, blks2imgs. Examples -------- >>> blks, imgsInfo = imgs2blks(imgspathes, [8, 8, 1], 'symmetric') """ logging.info("---In imgs2blks...") # numpy ndarray H-W-C-N if isinstance(imgs, np.ndarray) and np.ndim(imgs) == 4: imgsShape = imgs.shape # compute padding params hpad, wpad, cpad = _padhwc(imgsShape, blksize) # pads images pimgs = padimgs(imgs, ((0, hpad), (0, wpad), (0, cpad), (0, 0)), padmode) # splits padded images into blocks bH-bW-bC-bN, # where bN = bN1+bN2+...+bNn # bN1: blks of image_1, bNn blks of image_n logging.info("---Out imgs2blks...") return pimgs2blks(pimgs, blksize), imgsShape # image path list elif isinstance(imgs, list): if len(imgs) == 0: return # process the first image numimgs = 0 flag, datatype, _, img = _imageinfo(imgs[0]) if not flag: raise TypeError('No an avaliable image!') return imgsShape = [] # blks[:,:,:,0], for concatenate, will be removed later blks = np.zeros((blksize[0], blksize[1], blksize[2], 1), datatype) # split the rest images for imgpath in imgs: flag, _, _, img = _imageinfo(imgpath) if flag: # yes, it's an image imgsShape.append(img.shape) # compute padding params hpad, wpad, cpad = _padhwc(imgsShape[numimgs], blksize) # pads images pimgs = padimgs( img, ((0, hpad), (0, wpad), (0, cpad)), padmode) # splits padded images into blocks bH-bW-bC-bN, # where bN = bN1+bN2+...+bNn # bN1: blks of image_1, bNn blks of image_n blks = np.concatenate( (blks, pimgs2blks(pimgs, blksize)), axis=3) numimgs = numimgs + 1 if numimgs != 0: logging.info("---Out imgs2blks...") return blks[:, :, :, 1:], imgsShape # blks[:,:,:,0] all zeros else: raise TypeError('No avaliable image!') # return patches else: raise TypeError( '"imgs" should be a path list or H-W-C-N numpy ndarray!') logging.info("---Out imgs2blks.")
def _get_pimgshape(imgShape, blkSize): hpad, wpad, cpad = _padhwc(imgShape, blkSize) pH = imgShape[0] + hpad pW = imgShape[1] + wpad pC = imgShape[2] + cpad return (pH, pW, pC) def _rmsingledim(arr): if arr.shape[2] == 1: # Gray arr = np.reshape(arr, arr.shape[0:2]) return arr
[docs]def blks2imgs(blks, imgsShape, index=None, tofolder=None): r""" Fight image blocks back to images. Parameters ---------- blks : {array_like} A bH-bW-bC-bN numpy ndarray, where, bH, bW, bC, bN specify height, width, channels, number of images respectivelly. If blks Contains Gray Images and RGB Images, then bC = 3, and Gray Images is copied. imgsShape : {tuple or list} Specify each image's size. index : {int, optional} The image that you want to fight back. tofolder : {str (path), optional} Save specified images into files: image_0.png, image_i.png, ... , image_N.png Returns ------- out : {ndarray or bool} A list of image numpy ndarray(H-W-C). See Also -------- imgs2ptcs, imgs2blks. """ logging.info("---In blks2imgs...") if np.ndim(blks) != 4: raise TypeError( "blks must be a bH-bW-bC-bN 4-dimentional numpy ndarray!") if len(imgsShape) == 0: raise ValueError("You must tell me images's shape in blks!") if type(imgsShape) in (list, tuple): numimgs = len(imgsShape) if index is None: # all image index = range(0, numimgs) if tofolder is not None and (not os.path.isdir(tofolder)): raise TypeError('"tofolder" should be an available path!') imgvaluetype = blks.dtype imgsPos = [0] blksSize = blks.shape bH, bW, bC, bN = blksSize blkSize = [bH, bW, bC] for imgShape in imgsShape: pH, pW, pC = _get_pimgshape(imgShape, blkSize) mnBlock = np.array([pH, pW, pC]) / np.array([bH, bW, bC]) numblks1 = np.prod(mnBlock) imgsPos.append(imgsPos[-1] + numblks1) numFightBack = len(index) imgsShapeFightBack = [] for idx in index: imgsShapeFightBack.append(imgsShape[idx]) imgs = [] for n in range(0, numFightBack): imgShape = imgsShapeFightBack[n] pH, pW, pC = _get_pimgshape(imgShape, blkSize) arr = np.zeros([pH, pW, pC], imgvaluetype) cnt = int(imgsPos[index[n]]) for i in range(0, pH, bH): for j in range(0, pW, bW): for k in range(0, pC, bC): arr[i:bH + i, j:bW + j, k:bC + k] = blks[:, :, :, cnt] cnt = cnt + 1 img = _rmsingledim(arr[0:imgShape[0], 0:imgShape[1], 0:imgShape[2]]) imgs.append(img) if tofolder is not None: imwriteadv(tofolder + '/image_' + str(n) + '.png', img) logging.info("---Out blks2imgs.") return imgs # list contains N images numpy ndarray