How can I efficiently simulate image compression artifacts in Python? - python

I'm training a neural net using simulated images, and one of the things that happens in real life is low quality JPEG compression. It fuzzes up sharp edges in a particular way. Does anyone have an efficient way to simulate these effects? By that I mean create a corrupted version of a clean input. The images are grayscale, stored as numpy arrays.

Thanks to the answers in the comments, here is a solution which saves the image as JPEG and reads it back in, all in memory using standard python libraries.
import io
import imageio
# Image is 2D numpy array, q is quality 0-100
def jpegBlur(im,q):
buf = io.BytesIO()
imageio.imwrite(buf,im,format='jpg',quality=q)
s = buf.getbuffer()
return imageio.imread(s,format='jpg')
In my function I also pre- and post-scaled the image to convert from float64 to uint8 and back again, but this is the basic idea.

Related

Save 32-bit floating point TIFF image

I'm trying to save a 32-bit floating point image (stored as a Numpy array) as a TIFF file using tifffile.py.
import numpy as np
import tifffile
image = np.random.rand(500, 500, 3).astype(np.float32)
tifffile.imsave('image.tiff', image)
However, when viewing the output of the above code in Eye of Gnome, the image is entirely blank.
I think the problem is that not all tools support multi-channel TIFFs with 32-bits per channel. For example, as far as I can tell Python's PIL library does not. But I think tifffile.py does, because if I use your code I get a TIFF that opens, and looks reasonable, in GIMP:
From what I read, Photoshop can read 32-bit TIFFs too. So I think the TIFF file contains your image, but whether it works for you or not depends on what you want to do with it next.
This question might be relevant too, although it's about using 16-bit integers not floats: Python: Read and write TIFF 16 bit , three channel , colour images

Resize CSV data using Python and Keras

I have CSV files that I need to feed to a Deep-Learning network. Currently my CSV files are of size 360*480, but the network restricts them to be of size 224*224. I am using Python and Keras for the deep-learning part. So how can I resize the matrices?
I was thinking that since aspect ratio is 3:4, so if I resize them to 224:(224*4/3) = 224:299, and then crop the width of the matrix to 224, it could serve the purpose. But I cannot find a suitable function to do that. Please suggest.
I think you're looking for cv.resize() if you're using images.
If not, try numpy.ndarray.resize()
Image processing
If you want to do nontrivial alterations to the data as images (i.e. interpolating between pixel values, assuming that they represent photographs) then you might want to use proper image processing libraries for that. You'd need to treat them not as raw matrixes (csv of numbers) but convert them to rgb images, do the transformations you desire, and convert them back to a numpy matrix.
OpenCV (https://docs.opencv.org/3.4/da/d6e/tutorial_py_geometric_transformations.html)
or Pillow (https://pillow.readthedocs.io/en/3.1.x/reference/Image.html) might be useful to do that.
I found a short and simple way to solve this. This uses the Python Image Library/Pillow.
import numpy as np
import pylab as pl
from PIL import Image
matrix = np.array(list(csv.reader(open('./path/mat.csv', "r"), delimiter=","))).astype("uint8") #read csv
imgObj = Image.fromarray(matrix) #convert matrix to Image object
resized_imgObj = img.resize((224,224)) #resize Image object
imgObj.show()
resized_imgObj.show()
resized_matrix = np.asarray(img) #convert Image object to matrix
While numpy module also has a resize function, but it is not as useful as the aforementioned way.
When I tried it, the resized matrix had lost all the intricacies and aesthetic aspect of the original matrix. This is probably due to the fact that numpy.ndarray.resize doesn't interpolate and missing entries are filled with zeros.
So, for this case Image.resize() is more useful.
You could also convert the csv file to a list, truncate the list, and then convert the list to a numpy array and then use np.reshape.

Load portions of matrix into RAM

I'm writing some image processing routines for a micro-controller that supports MicroPython. The bad news is that it only has 0.5 MB of RAM. This means that if I want to work with relatively big images/matrices like 256x256, I need to treat it as a collection of smaller matrices (e.g. 32x32) and perform the operation on them. Leaving at aside the fact of reconstructing the final output of the orignal (256x256) matrix from its (32x32) submatrices, I'd like to focus on how to do the loading/saving from/to disk (an SD card in this case) of this smaller matrices from a big image.
Given that intro, here is my question: Assuming I have a 256x256 on disk that I'd like to apply some operation onto (e.g. convolution), what's the most convenient way of storing that image so it's easy to load it into 32x32 image patches? I've seen there is a MicroPython implementation of the pickle module, is this a good idea for my problem?
Sorry, but your question contains the answer - if you need to work with 32x32 tiles, the best format is that which represents your big image as a sequence of tiles (and e.g. not as one big 256x256 image, though reading tiles out of it is also not a rocket science and should be fairly trivial to code in MicroPython, though 32x32 tiles would be more efficient of course).
You don't describe the exact format of your images, but I wouldn't use pickle module for it, but store images as raw bytes and load them into array.array() objects (using inplace .readinto() operation).

Numpy array to image is blurry

I'm trying to save a numpy array as a png but the output is always blurry or the size of the image is very small. I've tried looking around SO and various other sources but I haven't been able to figure this one out.
(1) Using the following technique I get an image of the appropriate size (800x600px) but the matrix is blurry:
import matplotlib.pyplot as plt
plt.imshow(matrix)
plt.savefig(filename)
(2) Using another technique, the image is very small (60x60px) but the matrix is not blurry:
import matplotlib
matplotlib.image.imsave('name.png', array)
(3) After running my python program to produce a numpy array A, if I then run the command
matshow(A)
and then I hit the save icon to save the image, the result is an image of a larger size (800x600px) and the matrix is not blurry.
Using technique (3) wouldn't be an issue, but the thing is I have a lot of numpy arrays that I need to save as images, so it would be very time consuming to use technique (3) for each array.
Note: I can't post the images because I don't have enough reputation, so here is a link to them instead: https://www.dropbox.com/sh/mohtpm97xyy8ahi/AACgIpY5ECBDIbcnNRS9kd8La?dl=0
If anyone has had success producing clearer images of a larger size, like those in technique 3, any insight would be much appreciated.

What is the difference between a PIL Image from PIL.Image.open and a NumPy Image matplotlib.image.imread ?

I would like to know why I should or shouldn't use a matplotlib image over a PIL image. I know that matplotlib uses PIL to load any image that is not a PNG, but what is the advantage in having it in a numpy array over the PIL backend representation?
The PIL API includes function for performing a wide range of image manipulations. But of course, it does not provide a function for all conceivable operations. Numpy is useful when you have a mathematical operation to perform on the image which is not built into the PIL API. PIL has a way of altering pixels one-by-one but because if its reliance on Python loops it can be a very slow way to manipulate a large image (or many images).
Numpy math is relatively fast and it has an expressive syntax which
can make coding new image manipulations easier. Moreover, scipy has many additional image manipulating functions which can be applied to numpy arrays.
Here are a few examples:
emboss
converting rgb to hsv
replacing a color

Categories