mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-13 17:45:20 +08:00
@@ -158,3 +158,6 @@
|
||||
|
||||
- Fedor Morozov
|
||||
Drawing: Wu's anti-aliased circle
|
||||
|
||||
- Michael Hansen
|
||||
novice submodule
|
||||
|
||||
@@ -17,7 +17,8 @@ DEFAULT_COLORS = ('red', 'blue', 'yellow', 'magenta', 'green',
|
||||
'indigo', 'darkorange', 'cyan', 'pink', 'yellowgreen')
|
||||
|
||||
|
||||
color_dict = rgb_colors.__dict__
|
||||
color_dict = dict((k, v) for k, v in six.iteritems(rgb_colors.__dict__)
|
||||
if isinstance(v, tuple))
|
||||
|
||||
|
||||
def _rgb_vector(color):
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 186 B |
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
skimage.novice
|
||||
==============
|
||||
A special Python image submodule for beginners.
|
||||
|
||||
Description
|
||||
-----------
|
||||
``skimage.novice`` provides a simple image manipulation interface for
|
||||
beginners. It allows for easy loading, manipulating, and saving of image
|
||||
files.
|
||||
|
||||
This module is primarily intended for teaching and differs significantly from
|
||||
the normal, array-oriented image functions used by scikit-image.
|
||||
|
||||
.. note::
|
||||
|
||||
This module uses the Cartesian coordinate system, where the origin is at
|
||||
the lower-left corner instead of the upper-right and the order is x, y
|
||||
instead of row, column.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
We can create a Picture object open opening an image file
|
||||
>>> from skimage import novice
|
||||
>>> from skimage import data
|
||||
>>> picture = novice.open(data.data_dir + '/chelsea.png')
|
||||
|
||||
Pictures know their format
|
||||
>>> print picture.format
|
||||
png
|
||||
|
||||
... and where they came from
|
||||
>>> print picture.path.endswith('chelsea.png')
|
||||
True
|
||||
|
||||
... and their size
|
||||
>>> print picture.size
|
||||
(451, 300)
|
||||
>>> print picture.width
|
||||
451
|
||||
|
||||
Changing `size` resizes the picture.
|
||||
>>> picture.size = (45, 30)
|
||||
|
||||
You can iterate over pixels, which have RGB values between 0 and 255,
|
||||
and know their location in the picture.
|
||||
>>> for pixel in picture:
|
||||
... if (pixel.red > 128) and (pixel.x < picture.width):
|
||||
... pixel.red /= 2
|
||||
|
||||
Pictures know if they've been modified from the original file
|
||||
>>> print picture.modified
|
||||
True
|
||||
>>> print picture.path
|
||||
None
|
||||
|
||||
Pictures can be indexed like arrays
|
||||
>>> picture[0:20, 0:20] = (0, 0, 0)
|
||||
|
||||
Saving the picture updates the path attribute, format, and modified state.
|
||||
>>> picture.save('save-demo.jpg')
|
||||
>>> print picture.path.endswith('save-demo.jpg')
|
||||
True
|
||||
>>> print picture.format
|
||||
jpeg
|
||||
>>> print picture.modified
|
||||
False
|
||||
|
||||
"""
|
||||
from ._novice import Picture, open, colors, color_dict
|
||||
|
||||
|
||||
__all__ = ['Picture', 'open', 'colors', 'color_dict']
|
||||
@@ -0,0 +1,424 @@
|
||||
import os
|
||||
import imghdr
|
||||
from collections import namedtuple
|
||||
|
||||
import numpy as np
|
||||
from skimage import io
|
||||
from skimage import img_as_ubyte
|
||||
from skimage.transform import resize
|
||||
from skimage.color import color_dict
|
||||
from skimage._shared import six
|
||||
|
||||
|
||||
# Convert colors from `skimage.color` to uint8 and allow access through
|
||||
# dict or a named tuple.
|
||||
color_dict = dict((name, tuple(int(255 * c + 0.5) for c in rgb))
|
||||
for name, rgb in six.iteritems(color_dict))
|
||||
colors = namedtuple('colors', color_dict.keys())(**color_dict)
|
||||
|
||||
|
||||
def open(path):
|
||||
"""Return Picture object from the given image path."""
|
||||
return Picture(path=os.path.abspath(path))
|
||||
|
||||
|
||||
def _verify_picture_index(index):
|
||||
"""Raise error if picture index is not a 2D index/slice."""
|
||||
if not (isinstance(index, tuple) and len(index) == 2):
|
||||
raise IndexError("Expected 2D index but got {!r}".format(index))
|
||||
|
||||
if all(isinstance(i, int) for i in index):
|
||||
return index
|
||||
|
||||
# In case we need to fix the array index, convert tuple to list.
|
||||
index = list(index)
|
||||
|
||||
for i, dim_slice in enumerate(index):
|
||||
# If either index is a slice, ensure index object returns 2D array.
|
||||
if isinstance(dim_slice, int):
|
||||
index[i] = dim_slice = slice(dim_slice, dim_slice + 1)
|
||||
|
||||
return tuple(index)
|
||||
|
||||
|
||||
def rgb_transpose(array):
|
||||
"""Return RGB array with first 2 axes transposed."""
|
||||
return np.transpose(array, (1, 0, 2))
|
||||
|
||||
|
||||
def array_to_xy_origin(image):
|
||||
"""Return view of image transformed from array to Cartesian origin."""
|
||||
return rgb_transpose(image[::-1])
|
||||
|
||||
|
||||
def xy_to_array_origin(image):
|
||||
"""Return view of image transformed from Cartesian to array origin."""
|
||||
return rgb_transpose(image[:, ::-1])
|
||||
|
||||
|
||||
class Pixel(object):
|
||||
"""A single pixel in a Picture.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
pic : Picture
|
||||
The Picture object that this pixel references.
|
||||
array : array_like
|
||||
Byte array with raw image data (RGB).
|
||||
x : int
|
||||
Horizontal coordinate of this pixel (left = 0).
|
||||
y : int
|
||||
Vertical coordinate of this pixel (bottom = 0).
|
||||
rgb : tuple
|
||||
RGB tuple with red, green, and blue components (0-255)
|
||||
|
||||
"""
|
||||
def __init__(self, pic, array, x, y, rgb):
|
||||
self._picture = pic
|
||||
self._x = x
|
||||
self._y = y
|
||||
self._red = self._validate(rgb[0])
|
||||
self._green = self._validate(rgb[1])
|
||||
self._blue = self._validate(rgb[2])
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
"""Horizontal location of this pixel in the parent image(left = 0)."""
|
||||
return self._x
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
"""Vertical location of this pixel in the parent image (bottom = 0)."""
|
||||
return self._y
|
||||
|
||||
@property
|
||||
def red(self):
|
||||
"""The red component of the pixel (0-255)."""
|
||||
return self._red
|
||||
|
||||
@red.setter
|
||||
def red(self, value):
|
||||
self._red = self._validate(value)
|
||||
self._setpixel()
|
||||
|
||||
@property
|
||||
def green(self):
|
||||
"""The green component of the pixel (0-255)."""
|
||||
return self._green
|
||||
|
||||
@green.setter
|
||||
def green(self, value):
|
||||
self._green = self._validate(value)
|
||||
self._setpixel()
|
||||
|
||||
@property
|
||||
def blue(self):
|
||||
"""The blue component of the pixel (0-255)."""
|
||||
return self._blue
|
||||
|
||||
@blue.setter
|
||||
def blue(self, value):
|
||||
self._blue = self._validate(value)
|
||||
self._setpixel()
|
||||
|
||||
@property
|
||||
def rgb(self):
|
||||
"""The RGB color components of the pixel (3 values 0-255)."""
|
||||
return (self.red, self.green, self.blue)
|
||||
|
||||
@rgb.setter
|
||||
def rgb(self, value):
|
||||
self._red, self._green, self._blue = (self._validate(v) for v in value)
|
||||
self._setpixel()
|
||||
|
||||
def _validate(self, value):
|
||||
"""Verifies that the pixel value is in [0, 255]."""
|
||||
try:
|
||||
value = int(value)
|
||||
if (value < 0) or (value > 255):
|
||||
raise ValueError()
|
||||
except ValueError:
|
||||
msg = "Expected an integer between 0 and 255, but got {0} instead!"
|
||||
raise ValueError(msg.format(value))
|
||||
|
||||
return value
|
||||
|
||||
def _setpixel(self):
|
||||
self._picture.xy_array[self._x, self._y] = self.rgb
|
||||
self._picture._array_modified()
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Pixel):
|
||||
return self.rgb == other.rgb
|
||||
|
||||
def __repr__(self):
|
||||
args = self.red, self.green, self.blue
|
||||
return "Pixel(red={0}, green={1}, blue={2})".format(*args)
|
||||
|
||||
|
||||
class Picture(object):
|
||||
"""A 2-D picture made up of pixels.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
path : str
|
||||
Path to an image file to load.
|
||||
array : array
|
||||
Raw RGB image data [0-255], with origin at top-left.
|
||||
xy_array : array
|
||||
Raw RGB image data [0-255], with origin at bottom-left.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Load an image from a file
|
||||
>>> from skimage import novice
|
||||
>>> from skimage import data
|
||||
>>> picture = novice.open(data.data_dir + '/chelsea.png')
|
||||
|
||||
Create a blank 100 pixel wide, 200 pixel tall white image
|
||||
>>> pic = Picture.from_size((100, 200), color=(255, 255, 255))
|
||||
|
||||
Use numpy to make an RGB byte array (shape is height x width x 3)
|
||||
>>> import numpy as np
|
||||
>>> data = np.zeros(shape=(200, 100, 3), dtype=np.uint8)
|
||||
>>> data[:, :, 0] = 255 # Set red component to maximum
|
||||
>>> pic = Picture(array=data)
|
||||
|
||||
Get the bottom-left pixel
|
||||
>>> pic[0, 0]
|
||||
Pixel(red=255, green=0, blue=0)
|
||||
|
||||
Get the top row of the picture
|
||||
>>> pic[:, pic.height-1]
|
||||
Picture(100 x 1)
|
||||
|
||||
Set the bottom-left pixel to black
|
||||
>>> pic[0, 0] = (0, 0, 0)
|
||||
|
||||
Set the top row to red
|
||||
>>> pic[:, pic.height-1] = (255, 0, 0)
|
||||
|
||||
"""
|
||||
def __init__(self, path=None, array=None, xy_array=None):
|
||||
self._modified = False
|
||||
self.scale = 1
|
||||
self._path = None
|
||||
self._format = None
|
||||
|
||||
n_args = len([a for a in [path, array, xy_array] if a is not None])
|
||||
if n_args != 1:
|
||||
msg = "Must provide a single keyword arg (path, array, xy_array)."
|
||||
ValueError(msg)
|
||||
elif path is not None:
|
||||
self.array = img_as_ubyte(io.imread(path))
|
||||
self._path = path
|
||||
self._format = imghdr.what(path)
|
||||
elif array is not None:
|
||||
self.array = array
|
||||
elif xy_array is not None:
|
||||
self.xy_array = xy_array
|
||||
|
||||
@staticmethod
|
||||
def from_size(size, color='black'):
|
||||
"""Return a Picture of the specified size and a uniform color.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
size : tuple
|
||||
Width and height of the picture in pixels.
|
||||
color : tuple or str
|
||||
RGB tuple with the fill color for the picture [0-255] or a valid
|
||||
key in `color_dict`.
|
||||
"""
|
||||
if isinstance(color, six.string_types):
|
||||
color = color_dict[color]
|
||||
rgb_size = tuple(size) + (3,)
|
||||
array = np.ones(rgb_size, dtype=np.uint8) * color
|
||||
return Picture(array=array)
|
||||
|
||||
@property
|
||||
def array(self):
|
||||
"""Image data stored as numpy array."""
|
||||
return self._array
|
||||
|
||||
@array.setter
|
||||
def array(self, array):
|
||||
self._array = array
|
||||
self._xy_array = array_to_xy_origin(array)
|
||||
|
||||
@property
|
||||
def xy_array(self):
|
||||
"""Image data stored as numpy array with origin at the bottom-left."""
|
||||
return self._xy_array
|
||||
|
||||
@xy_array.setter
|
||||
def xy_array(self, array):
|
||||
self._xy_array = array
|
||||
self._array = xy_to_array_origin(array)
|
||||
|
||||
def save(self, path):
|
||||
"""Saves the picture to the given path.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : str
|
||||
Path (with file extension) where the picture is saved.
|
||||
"""
|
||||
io.imsave(path, self._rescale(self.array))
|
||||
self._modified = False
|
||||
self._path = os.path.abspath(path)
|
||||
self._format = imghdr.what(path)
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
"""The path to the picture."""
|
||||
return self._path
|
||||
|
||||
@property
|
||||
def modified(self):
|
||||
"""True if the picture has changed."""
|
||||
return self._modified
|
||||
|
||||
def _array_modified(self):
|
||||
self._modified = True
|
||||
self._path = None
|
||||
|
||||
@property
|
||||
def format(self):
|
||||
"""The image format of the picture."""
|
||||
return self._format
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
"""The size (width, height) of the picture."""
|
||||
return self.xy_array.shape[:2]
|
||||
|
||||
@size.setter
|
||||
def size(self, value):
|
||||
# Don't resize if no change in size
|
||||
if (value[0] != self.width) or (value[1] != self.height):
|
||||
# skimage dimensions are flipped: y, x
|
||||
new_size = (int(value[1]), int(value[0]))
|
||||
new_array = resize(self.array, new_size, order=0)
|
||||
self.array = img_as_ubyte(new_array)
|
||||
|
||||
self._array_modified()
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
"""The width of the picture."""
|
||||
return self.size[0]
|
||||
|
||||
@width.setter
|
||||
def width(self, value):
|
||||
self.size = (value, self.height)
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
"""The height of the picture."""
|
||||
return self.size[1]
|
||||
|
||||
@height.setter
|
||||
def height(self, value):
|
||||
self.size = (self.width, value)
|
||||
|
||||
def _repr_png_(self):
|
||||
return io.Image(self._rescale(self.array))._repr_png_()
|
||||
|
||||
def show(self):
|
||||
"""Display the image."""
|
||||
io.imshow(self._rescale(self.array))
|
||||
io.show()
|
||||
|
||||
def _makepixel(self, x, y):
|
||||
"""Create a Pixel object for a given x, y location."""
|
||||
rgb = self.xy_array[x, y]
|
||||
return Pixel(self, self.array, x, y, rgb)
|
||||
|
||||
def _rescale(self, array):
|
||||
"""Rescale image according to scale factor."""
|
||||
if self.scale == 1:
|
||||
return array
|
||||
new_size = (self.height * self.scale, self.width * self.scale)
|
||||
return img_as_ubyte(resize(array, new_size, order=0))
|
||||
|
||||
def _get_channel(self, channel):
|
||||
"""Return a specific dimension out of the raw image data slice."""
|
||||
return self._array[:, :, channel]
|
||||
|
||||
def _set_channel(self, channel, value):
|
||||
"""Set a specific dimension in the raw image data slice."""
|
||||
self._array[:, :, channel] = value
|
||||
|
||||
@property
|
||||
def red(self):
|
||||
"""The red component of the pixel (0-255)."""
|
||||
return self._get_channel(0).ravel()
|
||||
|
||||
@red.setter
|
||||
def red(self, value):
|
||||
self._set_channel(0, value)
|
||||
|
||||
@property
|
||||
def green(self):
|
||||
"""The green component of the pixel (0-255)."""
|
||||
return self._get_channel(1).ravel()
|
||||
|
||||
@green.setter
|
||||
def green(self, value):
|
||||
self._set_channel(1, value)
|
||||
|
||||
@property
|
||||
def blue(self):
|
||||
"""The blue component of the pixel (0-255)."""
|
||||
return self._get_channel(2).ravel()
|
||||
|
||||
@blue.setter
|
||||
def blue(self, value):
|
||||
self._set_channel(2, value)
|
||||
|
||||
@property
|
||||
def rgb(self):
|
||||
"""The RGB color components of the pixel (3 values 0-255)."""
|
||||
return self.xy_array
|
||||
|
||||
@rgb.setter
|
||||
def rgb(self, value):
|
||||
self.xy_array[:] = value
|
||||
|
||||
def __iter__(self):
|
||||
"""Iterates over all pixels in the image."""
|
||||
for x in range(self.width):
|
||||
for y in range(self.height):
|
||||
yield self._makepixel(x, y)
|
||||
|
||||
def __getitem__(self, xy_index):
|
||||
"""Return `Picture`s for slices and `Pixel`s for indexes."""
|
||||
xy_index = _verify_picture_index(xy_index)
|
||||
if all(isinstance(index, int) for index in xy_index):
|
||||
return self._makepixel(*xy_index)
|
||||
else:
|
||||
return Picture(xy_array=self.xy_array[xy_index])
|
||||
|
||||
def __setitem__(self, xy_index, value):
|
||||
xy_index = _verify_picture_index(xy_index)
|
||||
if isinstance(value, tuple):
|
||||
self[xy_index].rgb = value
|
||||
elif isinstance(value, Picture):
|
||||
self.xy_array[xy_index] = value.xy_array
|
||||
else:
|
||||
raise TypeError("Invalid value type")
|
||||
self._array_modified()
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Picture):
|
||||
raise NotImplementedError()
|
||||
return np.all(self.array == other.array)
|
||||
|
||||
def __repr__(self):
|
||||
return "Picture({0} x {1})".format(*self.size)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
@@ -0,0 +1,272 @@
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import assert_equal, raises, assert_allclose
|
||||
from skimage import novice
|
||||
from skimage.novice._novice import (array_to_xy_origin, xy_to_array_origin,
|
||||
rgb_transpose)
|
||||
from skimage import data_dir
|
||||
|
||||
|
||||
IMAGE_PATH = os.path.join(data_dir, "chelsea.png")
|
||||
SMALL_IMAGE_PATH = os.path.join(data_dir, "block.png")
|
||||
|
||||
|
||||
def _array_2d_to_RGB(array):
|
||||
return np.tile(array[:, :, np.newaxis], (1, 1, 3))
|
||||
|
||||
|
||||
def test_xy_to_array_origin():
|
||||
h, w = 3, 5
|
||||
array = np.arange(h * w).reshape(h, w, 1)
|
||||
out = xy_to_array_origin(array_to_xy_origin(array.copy()))
|
||||
assert np.allclose(out, array)
|
||||
|
||||
|
||||
def test_pic_info():
|
||||
pic = novice.open(IMAGE_PATH)
|
||||
assert_equal(pic.format, "png")
|
||||
assert_equal(pic.path, os.path.abspath(IMAGE_PATH))
|
||||
assert_equal(pic.size, (451, 300))
|
||||
assert_equal(pic.width, 451)
|
||||
assert_equal(pic.height, 300)
|
||||
assert not pic.modified
|
||||
assert_equal(pic.scale, 1)
|
||||
|
||||
|
||||
def test_pixel_iteration():
|
||||
pic = novice.open(SMALL_IMAGE_PATH)
|
||||
num_pixels = sum(1 for p in pic)
|
||||
assert_equal(num_pixels, pic.width * pic.height)
|
||||
|
||||
|
||||
def test_modify():
|
||||
pic = novice.open(SMALL_IMAGE_PATH)
|
||||
assert_equal(pic.modified, False)
|
||||
|
||||
for p in pic:
|
||||
if p.x < (pic.width / 2):
|
||||
p.red /= 2
|
||||
p.green /= 2
|
||||
p.blue /= 2
|
||||
|
||||
for p in pic:
|
||||
if p.x < (pic.width / 2):
|
||||
assert p.red <= 128
|
||||
assert p.green <= 128
|
||||
assert p.blue <= 128
|
||||
|
||||
s = pic.size
|
||||
pic.size = (pic.width / 2, pic.height / 2)
|
||||
assert_equal(pic.size, (int(s[0] / 2), int(s[1] / 2)))
|
||||
|
||||
assert pic.modified
|
||||
assert pic.path is None
|
||||
|
||||
|
||||
def test_pixel_rgb():
|
||||
pic = novice.Picture.from_size((3, 3), color=(10, 10, 10))
|
||||
pixel = pic[0, 0]
|
||||
pixel.rgb = np.arange(3)
|
||||
|
||||
assert_equal(pixel.rgb, np.arange(3))
|
||||
for i, channel in enumerate((pixel.red, pixel.green, pixel.blue)):
|
||||
assert_equal(channel, i)
|
||||
|
||||
pixel.red = 3
|
||||
pixel.green = 4
|
||||
pixel.blue = 5
|
||||
assert_equal(pixel.rgb, np.arange(3) + 3)
|
||||
|
||||
for i, channel in enumerate((pixel.red, pixel.green, pixel.blue)):
|
||||
assert_equal(channel, i + 3)
|
||||
|
||||
|
||||
def test_pixel_rgb_float():
|
||||
pixel = novice.Picture.from_size((1, 1))[0, 0]
|
||||
pixel.rgb = (1.1, 1.1, 1.1)
|
||||
assert_equal(pixel.rgb, (1, 1, 1))
|
||||
|
||||
|
||||
def test_modified_on_set():
|
||||
pic = novice.Picture(SMALL_IMAGE_PATH)
|
||||
pic[0, 0] = (1, 1, 1)
|
||||
assert pic.modified
|
||||
assert pic.path is None
|
||||
|
||||
|
||||
def test_modified_on_set_pixel():
|
||||
data = np.zeros(shape=(10, 5, 3), dtype=np.uint8)
|
||||
pic = novice.Picture(array=data)
|
||||
|
||||
pixel = pic[0, 0]
|
||||
pixel.green = 1
|
||||
assert pic.modified
|
||||
|
||||
|
||||
def test_update_on_save():
|
||||
pic = novice.Picture(array=np.zeros((3, 3, 3)))
|
||||
pic.size = (6, 6)
|
||||
assert pic.modified
|
||||
assert pic.path is None
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix=".jpg") as tmp:
|
||||
pic.save(tmp.name)
|
||||
|
||||
assert not pic.modified
|
||||
assert_equal(pic.path, os.path.abspath(tmp.name))
|
||||
assert_equal(pic.format, "jpeg")
|
||||
|
||||
|
||||
def test_indexing():
|
||||
array = 128 * np.ones((10, 10, 3), dtype=np.uint8)
|
||||
pic = novice.Picture(array=array)
|
||||
|
||||
pic[0:5, 0:5] = (0, 0, 0)
|
||||
for p in pic:
|
||||
if (p.x < 5) and (p.y < 5):
|
||||
assert_equal(p.rgb, (0, 0, 0))
|
||||
assert_equal(p.red, 0)
|
||||
assert_equal(p.green, 0)
|
||||
assert_equal(p.blue, 0)
|
||||
|
||||
pic[:5, :5] = (255, 255, 255)
|
||||
for p in pic:
|
||||
if (p.x < 5) and (p.y < 5):
|
||||
assert_equal(p.rgb, (255, 255, 255))
|
||||
assert_equal(p.red, 255)
|
||||
assert_equal(p.green, 255)
|
||||
assert_equal(p.blue, 255)
|
||||
|
||||
pic[5:pic.width, 5:pic.height] = (255, 0, 255)
|
||||
for p in pic:
|
||||
if (p.x >= 5) and (p.y >= 5):
|
||||
assert_equal(p.rgb, (255, 0, 255))
|
||||
assert_equal(p.red, 255)
|
||||
assert_equal(p.green, 0)
|
||||
assert_equal(p.blue, 255)
|
||||
|
||||
pic[5:, 5:] = (0, 0, 255)
|
||||
for p in pic:
|
||||
if (p.x >= 5) and (p.y >= 5):
|
||||
assert_equal(p.rgb, (0, 0, 255))
|
||||
assert_equal(p.red, 0)
|
||||
assert_equal(p.green, 0)
|
||||
assert_equal(p.blue, 255)
|
||||
|
||||
|
||||
def test_picture_slice():
|
||||
array = _array_2d_to_RGB(np.arange(0, 10)[np.newaxis, :])
|
||||
pic = novice.Picture(array=array)
|
||||
|
||||
x_slice = slice(3, 8)
|
||||
subpic = pic[:, x_slice]
|
||||
assert_allclose(subpic.array, array[x_slice, :])
|
||||
|
||||
|
||||
def test_move_slice():
|
||||
h, w = 3, 12
|
||||
array = _array_2d_to_RGB(np.linspace(0, 255, h * w).reshape(h, w))
|
||||
array = array.astype(np.uint8)
|
||||
|
||||
pic = novice.Picture(array=array)
|
||||
pic_orig = novice.Picture(array=array.copy())
|
||||
|
||||
# Move left cut of image to the right side.
|
||||
cut = 5
|
||||
rest = pic.width - cut
|
||||
temp = pic[:cut, :]
|
||||
temp.array = temp.array.copy()
|
||||
pic[:rest, :] = pic[cut:, :]
|
||||
pic[rest:, :] = temp
|
||||
|
||||
assert pic[rest:, :] == pic_orig[:cut, :]
|
||||
assert pic[:rest, :] == pic_orig[cut:, :]
|
||||
|
||||
|
||||
def test_negative_index():
|
||||
n = 10
|
||||
array = _array_2d_to_RGB(np.arange(0, n)[np.newaxis, :])
|
||||
# Test both x and y indices.
|
||||
pic = novice.Picture(array=array)
|
||||
assert pic[-1, 0] == pic[n - 1, 0]
|
||||
pic = novice.Picture(array=rgb_transpose(array))
|
||||
assert pic[0, -1] == pic[0, n - 1]
|
||||
|
||||
|
||||
def test_negative_slice():
|
||||
n = 10
|
||||
array = _array_2d_to_RGB(np.arange(0, n)[np.newaxis, :])
|
||||
# Test both x and y slices.
|
||||
pic = novice.Picture(array=array)
|
||||
assert pic[-3:, 0] == pic[n - 3:, 0]
|
||||
pic = novice.Picture(array=rgb_transpose(array))
|
||||
assert pic[0, -3:] == pic[0, n - 3:]
|
||||
|
||||
|
||||
def test_getitem_with_step():
|
||||
h, w = 5, 5
|
||||
array = _array_2d_to_RGB(np.linspace(0, 255, h * w).reshape(h, w))
|
||||
pic = novice.Picture(array=array)
|
||||
sliced_pic = pic[::2, ::2]
|
||||
assert sliced_pic == novice.Picture(array=array[::2, ::2])
|
||||
|
||||
|
||||
@raises(IndexError)
|
||||
def test_1d_getitem_raises():
|
||||
pic = novice.Picture.from_size((1, 1))
|
||||
pic[1]
|
||||
|
||||
|
||||
@raises(IndexError)
|
||||
def test_3d_getitem_raises():
|
||||
pic = novice.Picture.from_size((1, 1))
|
||||
pic[1, 2, 3]
|
||||
|
||||
|
||||
@raises(IndexError)
|
||||
def test_1d_setitem_raises():
|
||||
pic = novice.Picture.from_size((1, 1))
|
||||
pic[1] = 0
|
||||
|
||||
|
||||
@raises(IndexError)
|
||||
def test_3d_setitem_raises():
|
||||
pic = novice.Picture.from_size((1, 1))
|
||||
pic[1, 2, 3] = 0
|
||||
|
||||
|
||||
@raises(IndexError)
|
||||
def test_out_of_bounds_indexing():
|
||||
pic = novice.open(SMALL_IMAGE_PATH)
|
||||
pic[pic.width, pic.height]
|
||||
|
||||
|
||||
@raises(ValueError)
|
||||
def test_pixel_rgb_raises():
|
||||
pixel = novice.Picture.from_size((1, 1))[0, 0]
|
||||
pixel.rgb = (-1, -1, -1)
|
||||
|
||||
|
||||
@raises(ValueError)
|
||||
def test_pixel_red_raises():
|
||||
pixel = novice.Picture.from_size((1, 1))[0, 0]
|
||||
pixel.red = 256
|
||||
|
||||
|
||||
@raises(ValueError)
|
||||
def test_pixel_green_raises():
|
||||
pixel = novice.Picture.from_size((1, 1))[0, 0]
|
||||
pixel.green = 256
|
||||
|
||||
|
||||
@raises(ValueError)
|
||||
def test_pixel_blue_raises():
|
||||
pixel = novice.Picture.from_size((1, 1))[0, 0]
|
||||
pixel.blue = 256
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from numpy import testing
|
||||
testing.run_module_suite()
|
||||
Reference in New Issue
Block a user