I have an image here (DMM_a01_s01_e01_sdepth.PNG, it is basically a human depth map or something, I don't really know the details :( ):
It's very small (54x102) so here is a visualization:
But when I tried to resize it to 20x20 using this piece of code that I've made:
from scipy import misc
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
import math
import cv2
im = misc.imread('DMM_a01_s01_e01_sdepth.PNG')
def rgb2gray(rgb):
return np.dot(rgb[...,:3], [0.299, 0.587, 0.114])
if len(im.shape) ==3:
im = rgb2gray(im) # Convert RGB to grayscale
# Show image
plt.imshow(im, cmap = cm.Greys_r)
plt.show()
# Resize image
boxSize = 20
newImage= misc.imresize(im, (boxSize,boxSize), interp="bicubic")
plt.imshow(newImage, cmap = cm.Greys_r)
plt.show()
, the resized image is no longer the same as the orignal one:
How do I resize and still keep the structure of the image? Please help me, thank you very much :)
What you are asking for is impossible. Resizing of image is a destructive operation. You have 54x102 pixels (5508 pixels of data) and you are trying to fit that amount of data into a 20x20 image - that's just 400 pixels! You'll always lose some detail, structure etc. based on the algorithm you used - in this case scipy's.
Related
I'm a total newbie to Python.
What's the simplest algorithm by which I can zoom an image by a factor of 3?
I don't want to use the already made zoom functions available.
The task is moderately cumbersome, so I have shown a simple way to implement row zooming. You can similarly modify the indexes to implement column indexing for new_image as well.
# loading the image
from PIL import Image
import numpy as np
image = np.asarray( Image.open("img.jpg") )
import matplotlib.pyplot as plt
# create new image of correct size
m = len(image[0])
n = len(image)
factor = 3
new_image = np.zeros((factor*(n-1) + 1,factor*(m-1) + 1,3), dtype=int)
# implement row zooming
for i in range(n):
row = image[i]
for k in range(len(row)-1):
new_image[i][k*factor], new_image[i][(k+1)*factor] = row[k], row[k+1]
for mode in range(3):
# need mode as three colour channels in RGB
lo = int(min(row[k][mode], row[k+1][mode]))
hi = int(max(row[k][mode], row[k+1][mode]))
diff = int((hi-lo)//factor)
for x in range(factor-1):
new_image[i][k*factor+1+x][mode] = lo + (x*diff)
Let us say you have a .png image named lenna.png on you file system. You can load it and convert it to a numpy array like this
from PIL import Image
import numpy as np
image = np.asarray( Image.open("lenna.png") )
import matplotlib.pyplot as plt
plt.imshow(image)
plt.show()
Numpy offers a simple wayto increase the pixel resolution like this:
# Simply increase the resolution of the image by repeating the pixels
zoom_factor = 3
for i in range(2):
image = np.repeat(image, zoom_factor, axis=i)
If we plot the image it now simply has more pixels in each dimension:
You could then display only part of the image by cropping your new high resolution image like this
# Focus on any paricular region by croping it out
image = image[700:1000, 700:1000]
plt.imshow(image)
plt.show()
The result looks like this
Cheers!
I'm a newbie to tensorflow and keras, and I'm trying to create a CNN model for The Street View House Numbers (SVHN) dataset. The dataset contains color images, and I want to turn them in grayscale. I found some code on the web that claims they're turning image to grayscale, but it just changes colors.
People are reading the second image with a gray colormap. Is there any way to actually turn this image to grayscale?
(I do not know how to process an image in this kind of programming languages. If this is a dumb question, please forgive me and provide a brief explain.)
I provided images and code below, I'll be grateful for any help.
Code:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
#Read picture:
picture = plt.imread('google.jpg')
print("google logo's shape is: ",picture.shape) #(500, 500, 3)
#saving picture as an np array:
pic_array = np.array(picture)
#Turning image to grayscale
grayscale_pic = np.expand_dims(np.dot(pic_array[...,:3],[0.299, 0.587, 0.144]),axis = 0)
#Dimensions shifted, (probly my mistake):
grayscale_pic = np.moveaxis(grayscale_pic, 0, -1)
print("shape of grayscale pic = ", grayscale_pic.shape) # (500, 500, 1)
plt.imshow(picture) #Figure_1
plt.show()
plt.imshow(grayscale_pic) #Figure_2
plt.show()
U can convert a normal image to grayscale using opencv like this:
import cv2
gray = cv2.cvtColor(picture,cv2.COLOR_RGB2GRAY)
If u prefer numpy over opencv, then u can use this:
gray = np.dot(picture[...,:3], [0.2989, 0.5870, 0.1140])
You can use matplotlib with weights:
import numpy as np
import matplotlib.pyplot as plt
an_image = plt.imread('google.png')
rgb_weights = [0.2989, 0.5870, 0.1140]
grayscale_image = np.dot(an_image[..., :3], rgb_weights)
plt.axis('off')
plt.imshow(grayscale_image, cmap=plt.get_cmap("gray"), aspect='auto')
plt.show()
Output:
If you remove aspect='auto' parameter:
or you can use opencv
import cv2
an_image = cv2.imread("google.png")
grey_image = cv2.cvtColor(an_image, cv2.COLOR_BGR2GRAY)
or you can use PIL library
from PIL import Image
img = Image.open('google.png').convert('LA')
LA mode is L (8-bit pixels, black and white) with ALPHA desinged for .gif and .png. If your images are .jpeg use L.
Output:
There can be several ways to do this. One potential way is to utilize PIL(Pillow) library:
from PIL import Image
import matplotlib.pyplot as plt
picture = Image.open('google.jpg')
grayscale_pic = picture.convert('LA')
grayscale_pic.save('grayscale.png')
fig,ax = plt.subplots(nrows=1, ncols=2)
plt.subplot(1,2,1)
plt.imshow(picture)
plt.subplot(1,2,2)
plt.imshow(grayscale_pic)
plt.show()
Output:
I have a volume of image slices and their according masks. I've been trying to use skimage.segmentation library to mark the object in mind for each slice according to its mask.
import numpy as np
from skimage.segmentation import mark_boundaries
import matplotlib.pyplot as plt
def plot_marked_volume(marked_image_volume, mask):
for slice in range(len(marked_image_volume)):
if np.count_nonzero(mask[slice,:,:]):
plt.figure(figsize=(10,10))
edges_pz = mark_boundaries(marked_image_volume[slice,:,:], mask[slice].astype(np.int),
color=(1,0,0), mode='thin')
plt.imshow(edges_pz)
plt.title('slice ' + str(slice))
plt.show()
Here's a sample image and mask slice:
However running the code results in given boundaries with black backgrounds.
I am expecting an output like the following yellow boundAry (Ignore the 'CG'):
Any thoughts and suggestions as to what might be the issue is appreciated.
Although, I couldn't understand fully from your provided data, that what you were trying to do, but if you just want the mask to be shown in the original image, this is what you may like to do:
fig, axarr = plt.subplots(1, 3, figsize=(15, 40))
axarr[0].axis('off')
axarr[1].axis('off')
axarr[2].axis('off')
imgPath = "download.jpeg"
image = cv2.imread(imgPath)
#Show original image of same shape as of edges_pz or mask. Arguments should be image not its path.
axarr[0].imshow(image)
#Show the maks or edges_pz in your case
axarr[1].imshow(edges_pz)
#Show the image with combined mask and the original image, the shape of both image and mask should be same.
axarr[2].imshow(image)
axarr[2].imshow(edges_pz, alpha=0.4)
I hope this helps.
Based on a solution that I read at How to define the markers for Watershed in OpenCV?, I am trying apply watershed to grayscale data (not very visible but not all black), extracted from netcdf (precipitation data).
Here is a black and white version of the data (threshold at 0) so that you can see more easily, and the markers I want to use to define the different basins (basically just another threshold where precipitation is more intense).
The code I'm running is as follows:
import os,sys,string
from netCDF4 import Dataset as nc
import cv2
import numpy as np
import matplotlib.pyplot as mpl
import scipy.ndimage as ndimage
import scipy.spatial as spatial
from skimage import filter
from skimage.morphology import watershed
from scipy import ndimage
filename=["Cmorph-1999_01_03.nc"]
nc_data=nc(filename[0])
data=nc_data.variables["CMORPH"][23,0:250,250:750]
new_data=np.flipud(data)
ma_data=np.ma.masked_where(new_data<=0,new_data)
ma_conv=np.ma.masked_where(new_data<=2,new_data)
## Borders
tmp_data=ma_data.filled(0)
tmp_data[np.where(tmp_data!=0)]=255
bw_data=tmp_data.astype(np.uint8)
border = cv2.dilate(bw_data, None, iterations=5)
border = border - cv2.erode(border, None)
## Markers
tmp_conv=ma_conv.filled(0)
tmp_conv[np.where(tmp_conv!=0)]=255
bw_conv=tmp_conv.astype(np.uint8)
lbl, ncc = ndimage.label(bw_conv)
lbl = lbl * (255/ncc)
lbl[border == 255] = 255
lbl = lbl.astype(np.int32)
## Apply watershed
cv2.watershed(ma_data, lbl)
lbl[lbl == -1] = 0
lbl = lbl.astype(np.uint8)
result = 255 - lbl
I have the following error for the watershed in opencv-2.4.11/modules/imgproc/src/segmentation.cpp:
error: (-210) Only 8-bit, 3-channel input images are supported in function cvWatershed
For what I saw on the internet, this is due to the fact that the grayscale data is a 2D image and watershed needs a 3D image (from RGB). Indeed, I tried the script with a jpg image and I worked perfectly.
This problem is mentionned here but the answer given was finally rejected. And I can't find any more recent link answering the question.
To try to solve this, I created a 3D array from the 2D new_data:
new_data = new_data[..., np.newaxis]
test=np.append(new_data, new_data, axis=2)
test=np.append(new_data, test, axis=2)
But, as expected, it didn't solve the problem (same error message).
I also tried to save the plot from matplotlib to get RGB data:
fig = mpl.figure()
fig.add_subplot(111)
fig.tight_layout(pad=0)
mpl.contourf(ma_data,levels=np.arange(0,255.1,0.1))
fig.canvas.draw()
test_data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
test_data = test_data.reshape(fig.canvas.get_width_height()[::-1] + (3,))
But the size of the test_data created is different from ma_data (+ I can't get rid of the labels).
So, I am stuck here. Ideally, I want to apply the watershed on the 2D grayscale image directly and/or limit the number of operations as much as possible.
As yapws87 mentioned, there was indeed a problem with the format I was presenting to the watershed function.
Doing try_data=ma_data.astype(np.uint8) removed the error message.
Here is a minimal example that works now:
import os,sys
from netCDF4 import Dataset as nc
import cv2
import numpy as np
import scipy.ndimage as ndimage
from skimage.morphology import watershed
from scipy import ndimage
basename="/home/dcop696/Data/CMORPH/precip/CMORPH_V1.0/CRT/8km-30min/1999/"
filename=["Cmorph-1999_01_03.nc"]
fileslm=["/home/dcop696/Data/LSM/Cmorph_slm_8km.nc"]
nc_data=nc(basename+filename[0])
data=nc_data.variables["CMORPH"][23,0:250,250:750]
new_data=np.flipud(data)
ma_data=np.ma.masked_where(new_data<=0,new_data)
try_data=ma_data.astype(np.uint8)
## Building threshold
tmp_data=ma_data.filled(0)
tmp_data[np.where(tmp_data!=0)]=255
bw_data=tmp_data.astype(np.uint8)
## Building markers
ma_conv=np.ma.masked_where(new_data<=2,new_data)
tmp_conv=ma_conv.filled(0)
tmp_conv[np.where(tmp_conv!=0)]=255
bw_conv=tmp_conv.astype(np.uint8)
markers = ndimage.label(bw_conv)[0]
## Watershed
labels = watershed(-try_data, markers, mask=bw_data)
you can try changing your image fram gray to a BGR color space using
cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
before passing your image to watershed algorithm
The input is an image(document) from the scanner and my task is to crop the background and return only the document, just like this: Input Output
I've done this through thresholding and getbbox:
import matplotlib.pyplot as plt
import matplotlib.image as pli
from skimage.filters import threshold_otsu as otsu
from PIL import Image
cnh_gray = Image.open("cnh.jpg").convert('L')
cnh_gray.save('cnhgray.jpg')
img = pli.imread('cnhgray.jpg')
imagem = Image.open('cnhgray.jpg')
thresh = otsu(img)
mask = img < thresh
msk = Image.fromarray(mask,'L')
box = msk.getbbox()
crop = imagem.crop(box)
The problem is: The getbbox function doesn't work when the document isn't vertical. Since I don't know the angle, how can I rotate the image to use the getbbox funcion? If there's another function that I can use for inclined images instead of getbbox, please tell me.
Thanks for the help.