Using 32-bit Lab images in Tensorflow - python

I'm using skimage to convert RGB images to Lab colorspace but it seems that skimage uses float64 datatype while Tensorflow uses float32.
Is there any way to convert the 64-bit Lab image to 32-bit datatype? The documentation doesn't cover anything specific about this and I'm not sure if using image.astype(np.float32) is the way to go since it might damage the data precision (or not).
Here's a part of the code:
from skimage import color, io
import numpy as np
rgb = io.imread('Test.jpg') # Could be any shape
lab = color.rgb2lab(rgb)
converted = np.array(lab).astype(np.float32)
rgb = color.lab2rgb(converted)
The last line gives an error:
ValueError: Images of type float must be between -1 and 1.
and here's the Stack Trace:
File "C:\Anaconda3\lib\site-packages\skimage\color\colorconv.py", line 928, in lab2rgb
return xyz2rgb(lab2xyz(lab))
File "C:\Anaconda3\lib\site-packages\skimage\color\colorconv.py", line 855, in lab2xyz
arr = _prepare_colorarray(lab).copy()
File "C:\Anaconda3\lib\site-packages\skimage\color\colorconv.py", line 153, in _prepare_colorarray
return dtype.img_as_float(arr)
File "C:\Anaconda3\lib\site-packages\skimage\util\dtype.py", line 291, in img_as_float
return convert(image, np.float64, force_copy)
File "C:\Anaconda3\lib\site-packages\skimage\util\dtype.py", line 195, in convert
raise ValueError("Images of type float must be between -1 and 1.")
ValueError: Images of type float must be between -1 and 1.

Using x.astype(np.float32) is perfectly acceptable. You'll seldom if ever need that level of accuracy.
If you are not careful, however, you may accidentally cast an integer image (e.g., unsigned bytes, going from 0 to 255) into float. So the safest approach, that will rescale as necessary, is
from skimage import img_as_float
image = img_as_float(image).astype(np.float32)

This was a difficult bug to track down.
If you're using float32 then you get your error as described; however, the error will go away if you use float64 values instead.
Hope that helps! :)
Known bug source:
Scikit-image Issue

Related

Why does cv2.imread output a matrix of zeros for a 32-bit image even when using cv.IMREAD_ANYDEPTH?

I'm using OpenCV version 4.1.1 in Python and cannot get a legitimate reading for a 32-bit image, even when I use cv.IMREAD_ANYDEPTH. Without cv.IMREAD_ANYDEPTH, it returns as None type; with it, I get a matrix of zeros. The issue persists after reinstalling OpenCV. os.path.isfile returns True. The error was replicated on another computer. The images open in ImageJ, so I wouldn't think they're corrupted. I would rather use Skimage since it reads the images just fine, but I have to use OpenCV for what I'm working on. Any advice is appreciated.
img = cv2.imread(file,cv2.IMREAD_ANYDEPTH)
Link for the image: https://drive.google.com/file/d/1IiHbemsmn2gLW12RG3i9fLYZQW2u8sQw/view?usp=sharing
It appears to be some bug in how OpenCV loads such TIFF images. Pillow seems to load the image in a sensible way. Running
from PIL import Image
import numpy as np
img_pil = Image.open('example_image.tiff')
img_pil_cv = np.array(img_pil)
print(img_pil_cv.dtype)
print(img_pil_cv.max())
I get
int32
40950
as an output, which looks reasonable enough.
When I do
import cv2
img_cv = cv2.imread('example_image.tiff', cv2.IMREAD_ANYDEPTH)
print(img_cv.dtype)
print(img_cv.max())
I get
float32
5.73832e-41
which is obviously wrong.
Nevertheless, the byte array holding the pixel data is correct, it's just not being interpreted correctly. You can use numpy.ndarray.view to reinterpret the datatype of a numpy array, so that it's treated as an array if 32bit integers instead.
img_cv = cv2.imread('example_image.tiff', cv2.IMREAD_ANYDEPTH)
img_cv = img_cv.view(np.int32)
print(img_cv.dtype)
print(img_cv.max())
Which prints out
int32
40950
Since the maximum value is small enough for 16bit integer, let's convert the array and see what it looks like
img_cv_16bit = img_cv.astype(np.uint16)
cv2.imwrite('output_cv_16bit.png', img_cv_16bit)
OK, there are some bright spots, and a barely visible pattern. With a little adjustment, we can get something visible:
img_cv_8bit = np.clip(img_cv_16bit // 16, 0, 255).astype(np.uint8)
cv2.imwrite('output_cv_8bit.png', img_cv_8bit)
That looks quite reasonable now.

Why does the Sobel filter return a black square?

I'm trying to use sobel and prewitt filters from skimage for edge detection to compare the results, but for both I just get black squares!
That's my code:
import numpy as np
from skimage import filters
from PIL import Image
a=Image.open('F:/CT1.png').convert('L')
a.show()
a=np.asarray(a)
b=filters.sobel(a)
b=Image.fromarray(b)
b.show()
As most methods from scikit-image, the sobel function uses np.float64 for calculations, and thus converts your image appropriately to the range 0.0 ... 1.0. Following, your result b is also of type np.float64 with values in the same range. When now converting to some Pillow Image object, its mode is set to F, which is used for 32-bit floating point pixels.
Now, the documentation on Image.show tells us, for example:
On Windows, the image is opened with the standard PNG display utility.
It remains unclear, in which file format(?) the image is actually displayed. Seemingly, it's PNG, at least according to the temporary file name. But, for example, saving some Image object with mode F as PNG or JPG doesn't work! So, it seems, the image must be somehow converted to make it displayable. The first guess is, that some regular 8-bit image is chosen as default, since you get a nearly all black image, indicating that values 0 and maybe 1 are treated as "very dark". And, in fact, when using something like
b=Image.fromarray(b * 255)
the Windows image preview displays a proper image when using b.show().
So, that would be a workaround for the displaying.
Nevertheless, if you want to save the image instead, you don't necessarily need that conversion, but just need to use a proper file format to store those 32-bit information, TIFF for example:
b=Image.fromarray(b)
b.save('b.tiff')

How to convert a 1D python list containing image data into a numpy array and display it

Ok, I asked a similar question that revolved around vrep but it was a little specific when in fact a simpler python-based question would be more useful. I will, however, leave the question there should anyone be able to provide useful information.
Here is the question; How does one take a 1 dimensional list containing image data, convert it into a numpy array and then display it?
This is what I have so far:
im = np.array(image, dtype=np.uint8)
im.resize(128,128,3) #reshape this array into an image form (e.g. rather than 49152)
mlp.imshow(im)
pylab.show(im)
Here, image is returned from a simxGetVisionSensorImage (not important if you don't know vrep stuff) and is a list. I then try to create a numpy array and read the data in, turning it from a signed 8 bit integer into an unsigned 8 bit integer. I then resize it (it is a 49152 length list corresponding to a resolution of 128x128) and attempt to display it using either matplotlib or pylab.
Here are the includes should you need them:
import numpy as np
import matplotlib.pyplot as mlp
import pylab
the matplotlib.show command does not even show a window for the image. the pylab.show command throws this error:
Traceback (most recent call last):
File "vrep_epuck.py", line 59, in <module>
pylab.show(im)
File "/usr/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 244, in show
return _show(*args, **kw)
File "/usr/lib/python2.7/dist-packages/matplotlib/backend_bases.py", line 165, in __call__
if block:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Here is the link to the original vrep question should you want to see the whole code or see the vrep stuff:
vrep question
It would help to stay within the usual naming conventions.
Because then it would be more obvious that pyplot.show() does not take an image as argument. Thus, don't use pyplot.show(some_image_as_argument) but simply pyplot.show().
import matplotlib.pyplot as plt
image = ...
im = np.array(image, dtype=np.uint8)
im.resize(128,128,3)
plt.imshow(im)
plt.show()

Load OpenCV image from binary string

What I mean by binary string, is the raw content of image file (That's what wand.image.make_blob() returns)
Is there a way to load it in OpenCV ?
Edit:
cv2.imdecode() doesn't work
img = cv2.imdecode( buf=wand_img.make_blob(), flags=cv2.IMREAD_UNCHANGED)
TypeError: buf is not a numpy array, neither a scalar
Have you tried cv2.imdecode which takes an image buffer and turns it into a CvMat object? Though I am not sure about this one.
See : http://docs.opencv.org/3.0-beta/modules/imgcodecs/doc/reading_and_writing_images.html

Python code for basic fft of grid image

I'm trying to take an fft of an image in python, alter the transformed image and take a reverse fft. Specifically, I have a picture of a grid that I'd like to transform, then black out all but a central, narrow vertical slit of the transform, then take a reverse fft.
The code I'm working with now, for no alteration to transform plane:
import os
os.chdir('/Users/terra/Desktop')
import Image, numpy
i = Image.open('grid.png')
i = i.convert('L') #convert to grayscale
a = numpy.asarray(i) # a is readonly
b = abs(numpy.fft.rfft2(a))
j = Image.fromarray(b)
j.save('grid2.png')
As of now, I'm getting an error message:
Traceback (most recent call last):
File "/Users/terra/Documents/pic2.py", line 11, in
j.save('grid2.png')
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PIL/Image.py", line 1439, in save
save_handler(self, fp, filename)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PIL/PngImagePlugin.py", line 506, in _save
raise IOError, "cannot write mode %s as PNG" % mode
IOError: cannot write mode F as PNG
I'm very new to programming and Fourier transforms, so most related threads I've found online are over my head. Very specific help is greatly appreciated. Thanks!
The main problem is that the array contains floats after the FFT, but for it to be useful for PNG output, you need to have uint8s.
The simplest thing is to convert it to uint8 directly:
b = abs(numpy.fft.rfft2(a)).astype(numpy.uint8)
This probably will not produce the image you want, so you'll have to normalize the values in the array somehow before converting them to integers.

Categories