Image conversion and re-creation gives cryptic result - python

So I wrote this little code to try to convert RGB imge to Grayscale taken from this accepted answer. The problem, is that it shows a cryptic image with no likeness to original even when I am just re-creating the original. What do you think is the problem and how should we go about solving it? Also then I want to convert it to Grayscale as per the given array b.
Here's my code:
import matplotlib.image as img
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
a = img.imread('hCeFA.png')
a = a * 255 #Matplotlib gives float values between 0-1
b = a * np.array([0.3, 0.59, 0.11])
b = np.sum(b, axis = 2) / 3 #Grayscale conversion
img1 = Image.fromarray(a, 'RGB')
img1.save('my.png')
img1.show() #Gives a cryptic image
plt.imshow(a/255, interpolation='nearest') #Works fine
plt.show()

Better Read the image with the 'I'.
Like
imread('imageName.imgFormat',"I")
That will resolve the issue. It will read image in uint8 format, which i think you desire.

Related

How to use a picture from a plot for the further code

I tried to use a plot as image for my further code. I load an image in my pretrained model and my output is a tensor variable. In the next step I plot it with Image(img_hr).show(figsize=(18,15)). And after this I would like to use the picture from the plot to convert the colors. But the problem is, I cant use the variable img_hr because the type is tensor.
My idea was in the third last line to read the plot. The input for imagehsv = cv2.cvtColor(img_hr, cv2.COLOR_BGR2HSV) need to be an array and I dont know how to convert the plot.
Here is the error:
imagehsv = cv2.cvtColor(img_hr, cv2.COLOR_BGR2HSV)
error: OpenCV(4.5.2) :-1: error: (-5:Bad argument) in function 'cvtColor'
Overload resolution failed:
src is not a numpy array, neither a scalar
Expected Ptr<cv::UMat> for argument 'src'
I am new in python so please forgive me for any bad description or wrong vocabulary. I hope everything is clear otherwise feel free to ask.
Here is the picture of the plot:
Does anyone have an idea? Thanks a lot
from fastai import *
from fastai.vision import *
from fastai.callbacks.hooks import *
from fastai.utils.mem import *
import numpy as np
import cv2 as cv2
import matplotlib as mpl
import matplotlib.pyplot as plt
def acc_camvid(input, target):
target = target.squeeze(1)
mask = target != void_code
return (input.argmax(dim=1)[mask]==target[mask]).float().mean()
learn=load_learner(r'C:\pretrained_model')
image= r"C:\image.png"
img = open_image(image); img.shape
_,img_hr,b = learn.predict(img)
Image(img_hr).show(figsize=(18,15))
#image = cv2.imread(Image(img_hr))
imagehsv = cv2.cvtColor(img_hr, cv2.COLOR_BGR2HSV)
plt.imshow(fixColor(imagehsv))
fastai works with PIL Image types.
So your variable img_hr is an Image.
OpenCV uses NumPy ndarray types. You need to convert your Image to a ndarray:
_, img_hr, b = learn.predict(img)
img_hr = np.array(img_hr)
# PIL uses RGB channel order, not BGR like OpenCV default
imagehsv = cv2.cvtColor(img_hr, cv2.COLOR_RGB2HSV)
# Display your result in HSV color space
cv2.imshow("Image HSV", imagehsv)
cv2.waitKey()

skimage.transform.rotate: getting a completely black image on saving

I am working with python 3.6 and performing following functions on an image (read image, pad image, crop image, rotate image). I am either using skimage or basic python function. If I don't rotate the image then there is no warning. But if I rotate the image, I am getting following warning
/anaconda3/lib/python3.6/site-packages/skimage/util/dtype.py:122:
UserWarning: Possible precision loss when converting from int64 to
float64 .format(dtypeobj_in, dtypeobj_out))
When I try to view the image using imshow, image values seemed to be in the range of (1e-17) (https://ibb.co/cSfzb7). I guess image values got normalized somewhere but I am not able to find the location.
If I try to save the rotated image, I get a completely black image.
im = img_as_uint(image)
imsave(image_path, im, plugin='imageio')
I tried removing img_as_uint, using default imsave, using (freeimage, imagio) as plugin option
/anaconda3/lib/python3.6/site-packages/skimage/util/dtype.py:122:
UserWarning: Possible precision loss when converting from int64 to
float64 .format(dtypeobj_in, dtypeobj_out))
/anaconda3/lib/python3.6/site-packages/skimage/util/dtype.py:122:
UserWarning: Possible precision loss when converting from float64 to
uint16 .format(dtypeobj_in, dtypeobj_out))
/anaconda3/lib/python3.6/site-packages/skimage/io/_io.py:132:
UserWarning: /Users/ashisharora/google_Drive/madcat_arabic/lines/AAW_ARB_20061105.0017-S1_1_LDC0372_00z1.png is a low contrast image warn('%s is a low contrast image' % fname)
import sys
import argparse
import os
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
import skimage
from skimage.io import imread, imsave, imshow
from skimage.transform import rotate
from skimage import img_as_uint
im_wo_pad = imread(image_file_name)
im = pad_image(im_wo_pad)
region_initial = im[281:480, 2509:4766]
rotation_angle_in_rad = -0.00708
img2 = rotate(region_initial, degrees(rotation_angle_in_rad))
region_final = img2[15:298, 7:2263]
imshow(region_final)
def pad_image(image):
offset = 200
max_val = 255
height = image.shape[0]
im_pad = np.concatenate((max_val * np.ones((height, offset),
dtype=int), image), axis=1)
im_pad1 = np.concatenate((im_pad, max_val * np.ones((height, offset),
dtype=int)), axis=1)
width = im_pad1.shape[1]
im_pad2 = np.concatenate((max_val * np.ones((offset, width),
dtype=int), im_pad1), axis=0)
im_pad3 = np.concatenate((im_pad2, max_val * np.ones((offset, width),
dtype=int)), axis=0)
return im_pad3
I tried solutions posted on stack overflow but it is not working for my case. I would appreciate if someone can help.
By default, the skimage rotate function converts to float and scales the image values between 0 and 1. (See http://scikit-image.org/docs/dev/api/skimage.transform.html#skimage.transform.rotate)
Try using the preserve_range parameter and some type casting, e.g.,
img_rot = skimage.transform.rotate(img, rot_angle, preserve_range=True).astype(np.uint8)

convert image from CV_64F to CV_8U

I want to convert an image of type CV_64FC1 to CV_8UC1 in Python using OpenCV.
In C++, using convertTo function, we can easily convert image type using following code snippet:
image.convertTo(image, CV_8UC1);
I have searched on Internet but unable to find any solution without errors. Any function in Python OpenCV to convert this?
You can convert it to a Numpy array.
import numpy as np
# Convert source image to unsigned 8 bit integer Numpy array
arr = np.uint8(image)
# Width and height
h, w = arr.shape
It seems OpenCV Python APIs accept Numpy arrays as well. I've not tested it though. Please test it and let me know the result.
For those getting a black screen or lots of noise, you'll want to normalize your image first before converting to 8-bit. This is done with numpy directly as OpenCV uses numpy arrays for its images.
Before normalization, the image's range is from 4267.0 to -4407.0 in my case.
Now to normalize:
# img is a numpy array/cv2 image
img = img - img.min() # Now between 0 and 8674
img = img / img.max() * 255
Now that the image is between 0 and 255, we can convert to a 8-bit integer.
new_img = np.uint8(img)
This can also be done by img.astype(np.uint8).
I faced similar issue and when I trying to convert the image 64F to CV_U8 I would end up with a black screen.
This link will help you understand the datatypes and conversion. Below is the code that worked for me.
from skimage import img_as_ubyte
cv_image = img_as_ubyte(any_skimage_image)

Trouble with Canny Edge Detector - Returning black image

I'm trying to run the canny edge detector on this image:
With this code:
def edges(img):
from skimage import feature
img = Image.open(img)
img.convert('L')
array = np.array(img)
out = feature.canny(array, sigma=1, )
return Image.fromarray(out,'L')
edges('Q_3.jpg').save('Q_3_edges.jpg')
But I'm just getting a black image back. Any ideas what I could be doing wrong? I tried sigma of 1 and of 3.
I have the same situation and this helps for me. Before use the Canny filter, just convert your elements of image array to float32 type:
array = np.array(img)
array = array.astype('float32')
out = feature.canny(array, sigma=1, )
Your images need to be in the correct range for the relevant dtype, as discussed in the user manual here: http://scikit-image.org/docs/stable/user_guide/data_types.html
This should be automatically handled if you use the scikit-image image I/O functions:
from skimage import io
img = io.imread('Q_3.jpg')
So the issue was with the canny function returning and array of type boolean.
Oddly, setting the Image.fromarray mode to '1' didn't help. Instead this was the only way I could get it working; converting the output array to grayscale:
def edges(img):
from skimage import feature
img = Image.open(img)
img.convert('L')
array = np.array(img)
out = np.uint8(feature.canny(array, sigma=1, ) * 255)
return Image.fromarray(out,mode='L')
The problem happens when the image is loaded as float (i.e. in the range 0-1). The loader does that for some types of images. You can check the type of the loaded image by:
print(img.dtype)
If the output is something like float64 (i.e. not uint8), then your image is in the range 0-1.
Canny expects an image in the range 0-255. Therefore, the solution is as easy as:
from skimage import img_as_ubyte
img = io.imread("an_image.jpg")
img = img_as_ubyte(img)
Hope this helps,
The problem happens when the image is saved. You can save image with other library like matplotlib:
import numpy as np
import matplotlib.pyplot as plt
from skimage import feature
from skimage import io
def edges(img):
img = io.imread(img)
array = np.array(img)
out = feature.canny(array, sigma=1, )
return out
plt.imsave("canny.jpg", edges("input.jpg"), cmap="Greys")

how to save an array as a grayscale image with matplotlib/numpy?

I am trying to save a numpy array of dimensions 128x128 pixels into a grayscale image.
I simply thought that the pyplot.imsave function would do the job but it's not, it somehow converts my array into an RGB image.
I tried to force the colormap to Gray during conversion but eventhough the saved image appears in grayscale, it still has a 128x128x4 dimension.
Here is a code sample I wrote to show the behaviour :
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mplimg
from matplotlib import cm
x_tot = 10e-3
nx = 128
x = np.arange(-x_tot/2, x_tot/2, x_tot/nx)
[X, Y] = np.meshgrid(x,x)
R = np.sqrt(X**2 + Y**2)
diam = 5e-3
I = np.exp(-2*(2*R/diam)**4)
plt.figure()
plt.imshow(I, extent = [-x_tot/2, x_tot/2, -x_tot/2, x_tot/2])
print I.shape
plt.imsave('image.png', I)
I2 = plt.imread('image.png')
print I2.shape
mplimg.imsave('image2.png',np.uint8(I), cmap = cm.gray)
testImg = plt.imread('image2.png')
print testImg.shape
In both cases the results of the "print" function are (128,128,4).
Can anyone explain why the imsave function is creating those dimensions eventhough my input array is of a luminance type?
And of course, does anyone have a solution to save the array into a standard grayscale format?
Thanks!
With PIL it should work like this
from PIL import Image
I8 = (((I - I.min()) / (I.max() - I.min())) * 255.9).astype(np.uint8)
img = Image.fromarray(I8)
img.save("file.png")
There is also an alternative of using imageio. It provides an easy and convenient API and it is bundled with Anaconda. It can save grayscale images as a single color channel file.
Quoting the documentation
>>> import imageio
>>> im = imageio.imread('imageio:astronaut.png')
>>> im.shape # im is a numpy array
(512, 512, 3)
>>> imageio.imwrite('astronaut-gray.jpg', im[:, :, 0])
I didn't want to use PIL in my code and as noted in the question I ran into the same problem with pyplot, where even in grayscale, the file is saved in MxNx3 matrix.
Since the actual image on disk wasn't important to me, I ended up writing the matrix as is and reading it back "as-is" using numpy's save and load methods:
np.save("filename", image_matrix)
And:
np.load("filename.npy")
There is also a possibility to use scikit-image, then there is no need to convert numpy array into a PIL object.
from skimage import io
io.imsave('output.tiff', I.astype(np.uint16))

Categories

Resources