How to compare images and conbine into one image using python - python

I have a problem as follows, i have about 30 pieces of an image and i want to combine it into one like this image. How or any library in python can do that?

import cv2
import numpy as np
im1 = cv2.imread('data/abc1.jpg')
im2 = cv2.imread('data/abc2.jpg')
im_v = cv2.vconcat([im1, im1])
cv2.imwrite('data/dst/opencv_vconcat.jpg', im_v)

Related

Colour intensity is changing when stacking numpy image arrays

I am loading an image from here, which is saved as .nii.gz. The image opens fine (with a dimension of (497x497)), and when displayed using matplotlib, it shows with correct intensities, as shown below:
When we are trying to make it a 3 channel image, by stacking the numpy array, and after plotting it, the intensity changes, as shown below:
Any idea how to resolve this? The minimal code to reproduce the problem in google colaboratory is present here:
import cv2
import glob
import numpy as np
import nibabel as nib
import skimage.io as io
from nibabel import nifti1
import matplotlib.pyplot as plt
! wget "https://github.com/Jimut123/simply_junk/blob/main/image.nii.gz?raw=true" -O image.nii.gz
image_file_name = "image.nii.gz"
print(image_file_name)
epi_img = nib.load(image_file_name)
epi_img_data = epi_img.get_fdata()
epi_img_data = epi_img_data/epi_img_data.max()
# epi_img_data = epi_img_data[..., np.newaxis]
plt.imshow(epi_img_data)
plt.show()
total_mask = np.stack((epi_img_data,)*3, axis=-1)
plt.imshow(total_mask,cmap='gray')
plt.show()
Like for example this is a 3-channel image (RGB):
But this looks exactly like it's grayscale version. For the above image, when stacking numpy arrays, I cannot make the image look similar to the grayscale one.
If you scale it as Cristolph and Johan described, the 3-channel plot becomes identical:
epi_img_data -= epi_img_data.min()
epi_img_data /= epi_img_data.max()
total_mask = np.stack((epi_img_data,)*3, axis=-1)
plt.imshow(total_mask)

Python image library, Select random pictures from files

Hi I need some help with something I'm working on, I have this code that gets 2 pictures from 2 different folders and pastes it over each other creating 1 final merged image, what I want though is to merge two randomly selected pictures from the separate directories, thanks
from PIL import Image
import os
import random
import numpy as np
img1 = Image.open("/Users/Liam/Pictures/1/dfd.jpg").convert("RGBA")
img2 = Image.open("/Users/Liam/Pictures/2/face.png").convert("RGBA")
img1.paste(img2, (0,0), mask = img2)
img1.show()
It is actually pretty easy, check my example below
from PIL import Image
import os
import random
import numpy as np
basedir1 = "/Users/Liam/Pictures/1/"
basedir2 = "/Users/Liam/Pictures/2/"
first_image_list = os.listdir(basedir1)
second_image_list = os.listdir(basedir2)
img1 = Image.open(os.path.join(basedir1, random.choice(first_image_list))).convert("RGBA")
img2 = Image.open(os.path.join(basedir2, random.choice(second_image_list))).convert("RGBA")
img1.paste(img2, (0,0), mask = img2)
img1.show()

How to convert wand.image.Image to PIL.Image?

I spent whole day on this problem and did not see answer in stack overflow!
I tried this but did not work:
>> pil_image = Image.frombytes('RGBA', wand_image.size, wand_image.make_blob(format='png'), 'raw')
ValueError: not enough image data
I appreciate every solution.
This doesn't involve numpy:
pil_image = PIL.Image.open(io.BytesIO(wand_image.make_blob("png"))
This worked for me:
img_buffer = numpy.asarray(bytearray(wand_img.make_blob(format='png')), dtype='uint8')
bytesio = io.BytesIO(img_buffer)
pil_img = PIL.Image.open(bytesio)
one way is through numpy - meaning to export PIL image into numpy array and then read it by wand
from wand.image import Image
from IPython.display import display
with Image.from_array(np.array(img)) as ximg:
display(ximg)
or the other way around
from wand.image import Image
from matplotlib import cm
with Image(filename='rose:') as img:
array = np.array(img)
im = Image.fromarray(np.uint8(cm.gist_earth(array)*255))

Array to image with colour map

I have some data in a 2048x2048 array that I want to convert to an image.
import numpy as np
from PIL import Image
path = 'E:\\petra_2018_backup\\final\\raw\data\zn_2_run\\'
file = 'Zn_2_Pos1-01537.tif'
im = Image.open(path+file)
a = np.array(im)
img = Image.frombytes('CMYK', (2048, 2048), a) # pass in the bytestring
img.save('pic.pdf')
img.show()
This result is quite dark and also has a mixture of green and blue colours. I should mention that the attached picture is a screendump of the result as the result picture is to large to attach.
It would also be usefull if people can advice on a way to compress the resulting image.
I simply could not find a solution using pillow. So I started using scikit.
Code as follows:
import numpy as np
from skimage import io
import matplotlib.pyplot as plt
path = 'E:\\petra_2018_backup\\final\\raw\data\zn_2_run\\'
file = 'Zn_2_Pos1-01537.tif'
im =io.imread(path+file,as_gray=True)
b = np.array([im],dtype=np.uint16 )
b[b<150]=150 #Modification to array not included in original code
b[b>6000]=6000 #Modification to array not included in original code
c=b.squeeze()
fig = plt.figure()
ax = plt.subplot(111)
ax = io.imshow(c)
fig.savefig('result_figure.png',dpi=320)
It produces the following plot.

Convert 8 bit image to 24 bit [duplicate]

I have a matrix in the type of a Numpy array. How would I write it to disk it as an image? Any format works (png, jpeg, bmp...). One important constraint is that PIL is not present.
An answer using PIL (just in case it's useful).
given a numpy array "A":
from PIL import Image
im = Image.fromarray(A)
im.save("your_file.jpeg")
you can replace "jpeg" with almost any format you want. More details about the formats here
This uses PIL, but maybe some might find it useful:
import scipy.misc
scipy.misc.imsave('outfile.jpg', image_array)
EDIT: The current scipy version started to normalize all images so that min(data) become black and max(data) become white. This is unwanted if the data should be exact grey levels or exact RGB channels. The solution:
import scipy.misc
scipy.misc.toimage(image_array, cmin=0.0, cmax=...).save('outfile.jpg')
With matplotlib:
import matplotlib.image
matplotlib.image.imsave('name.png', array)
Works with matplotlib 1.3.1, I don't know about lower version. From the docstring:
Arguments:
*fname*:
A string containing a path to a filename, or a Python file-like object.
If *format* is *None* and *fname* is a string, the output
format is deduced from the extension of the filename.
*arr*:
An MxN (luminance), MxNx3 (RGB) or MxNx4 (RGBA) array.
There's opencv for python (documentation here).
import cv2
import numpy as np
img = ... # Your image as a numpy array
cv2.imwrite("filename.png", img)
useful if you need to do more processing other than saving.
Pure Python (2 & 3), a snippet without 3rd party dependencies.
This function writes compressed, true-color (4 bytes per pixel) RGBA PNG's.
def write_png(buf, width, height):
""" buf: must be bytes or a bytearray in Python3.x,
a regular string in Python2.x.
"""
import zlib, struct
# reverse the vertical line order and add null bytes at the start
width_byte_4 = width * 4
raw_data = b''.join(
b'\x00' + buf[span:span + width_byte_4]
for span in range((height - 1) * width_byte_4, -1, - width_byte_4)
)
def png_pack(png_tag, data):
chunk_head = png_tag + data
return (struct.pack("!I", len(data)) +
chunk_head +
struct.pack("!I", 0xFFFFFFFF & zlib.crc32(chunk_head)))
return b''.join([
b'\x89PNG\r\n\x1a\n',
png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, 6, 0, 0, 0)),
png_pack(b'IDAT', zlib.compress(raw_data, 9)),
png_pack(b'IEND', b'')])
... The data should be written directly to a file opened as binary, as in:
data = write_png(buf, 64, 64)
with open("my_image.png", 'wb') as fh:
fh.write(data)
Original source
See also: Rust Port from this question.
Example usage thanks to #Evgeni Sergeev: https://stackoverflow.com/a/21034111/432509
You can use PyPNG. It's a pure Python (no dependencies) open source PNG encoder/decoder and it supports writing NumPy arrays as images.
If you have matplotlib, you can do:
import matplotlib.pyplot as plt
plt.imshow(matrix) #Needs to be in row,col order
plt.savefig(filename)
This will save the plot (not the images itself).
for saving a numpy array as image, U have several choices:
1) best of other: OpenCV
import cv2
cv2.imwrite('file name with extension(like .jpg)', numpy_array)
2) Matplotlib
from matplotlib import pyplot as plt
plt.imsave('file name with extension(like .jpg)', numpy_array)
3) PIL
from PIL import Image
image = Image.fromarray(numpy_array)
image.save('file name with extension(like .jpg)')
4) ...
scipy.misc gives deprecation warning about imsave function and suggests usage of imageio instead.
import imageio
imageio.imwrite('image_name.png', img)
You can use 'skimage' library in Python
Example:
from skimage.io import imsave
imsave('Path_to_your_folder/File_name.jpg',your_array)
Addendum to #ideasman42's answer:
def saveAsPNG(array, filename):
import struct
if any([len(row) != len(array[0]) for row in array]):
raise ValueError, "Array should have elements of equal size"
#First row becomes top row of image.
flat = []; map(flat.extend, reversed(array))
#Big-endian, unsigned 32-byte integer.
buf = b''.join([struct.pack('>I', ((0xffFFff & i32)<<8)|(i32>>24) )
for i32 in flat]) #Rotate from ARGB to RGBA.
data = write_png(buf, len(array[0]), len(array))
f = open(filename, 'wb')
f.write(data)
f.close()
So you can do:
saveAsPNG([[0xffFF0000, 0xffFFFF00],
[0xff00aa77, 0xff333333]], 'test_grid.png')
Producing test_grid.png:
(Transparency also works, by reducing the high byte from 0xff.)
For those looking for a direct fully working example:
from PIL import Image
import numpy
w,h = 200,100
img = numpy.zeros((h,w,3),dtype=numpy.uint8) # has to be unsigned bytes
img[:] = (0,0,255) # fill blue
x,y = 40,20
img[y:y+30, x:x+50] = (255,0,0) # 50x30 red box
Image.fromarray(img).convert("RGB").save("art.png") # don't need to convert
also, if you want high quality jpeg's
.save(file, subsampling=0, quality=100)
matplotlib svn has a new function to save images as just an image -- no axes etc. it's a very simple function to backport too, if you don't want to install svn (copied straight from image.py in matplotlib svn, removed the docstring for brevity):
def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None, origin=None):
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
fig = Figure(figsize=arr.shape[::-1], dpi=1, frameon=False)
canvas = FigureCanvas(fig)
fig.figimage(arr, cmap=cmap, vmin=vmin, vmax=vmax, origin=origin)
fig.savefig(fname, dpi=1, format=format)
Imageio is a Python library that provides an easy interface to read and write a wide range of image data, including animated images, video, volumetric data, and scientific formats. It is cross-platform, runs on Python 2.7 and 3.4+, and is easy to install.
This is example for grayscale image:
import numpy as np
import imageio
# data is numpy array with grayscale value for each pixel.
data = np.array([70,80,82,72,58,58,60,63,54,58,60,48,89,115,121,119])
# 16 pixels can be converted into square of 4x4 or 2x8 or 8x2
data = data.reshape((4, 4)).astype('uint8')
# save image
imageio.imwrite('pic.jpg', data)
The world probably doesn't need yet another package for writing a numpy array to a PNG file, but for those who can't get enough, I recently put up numpngw on github:
https://github.com/WarrenWeckesser/numpngw
and on pypi: https://pypi.python.org/pypi/numpngw/
The only external dependency is numpy.
Here's the first example from the examples directory of the repository. The essential line is simply
write_png('example1.png', img)
where img is a numpy array. All the code before that line is import statements and code to create img.
import numpy as np
from numpngw import write_png
# Example 1
#
# Create an 8-bit RGB image.
img = np.zeros((80, 128, 3), dtype=np.uint8)
grad = np.linspace(0, 255, img.shape[1])
img[:16, :, :] = 127
img[16:32, :, 0] = grad
img[32:48, :, 1] = grad[::-1]
img[48:64, :, 2] = grad
img[64:, :, :] = 127
write_png('example1.png', img)
Here's the PNG file that it creates:
Also, I used numpngw.write_apng to create the animations in Voronoi diagram in Manhattan metric.
Assuming you want a grayscale image:
im = Image.new('L', (width, height))
im.putdata(an_array.flatten().tolist())
im.save("image.tiff")
If you happen to use [Py]Qt already, you may be interested in qimage2ndarray. Starting with version 1.4 (just released), PySide is supported as well, and there will be a tiny imsave(filename, array) function similar to scipy's, but using Qt instead of PIL. With 1.3, just use something like the following:
qImage = array2qimage(image, normalize = False) # create QImage from ndarray
success = qImage.save(filename) # use Qt's image IO functions for saving PNG/JPG/..
(Another advantage of 1.4 is that it is a pure python solution, which makes this even more lightweight.)
If you are working in python environment Spyder, then it cannot get more easier than to just right click the array in variable explorer, and then choose Show Image option.
This will ask you to save image to dsik, mostly in PNG format.
PIL library will not be needed in this case.
Use cv2.imwrite.
import cv2
assert mat.shape[2] == 1 or mat.shape[2] == 3, 'the third dim should be channel'
cv2.imwrite(path, mat) # note the form of data should be height - width - channel
In the folowing answer has the methods as proposed by #Nima Farhadi in time measurement.
The fastest is CV2 , but it's important to change colors order from RGB to BGR. The simples is matplotlib.
It's important to assure, that the array have unsigned integer format uint8/16/32.
Code:
#Matplotlib
from matplotlib import pyplot as plt
plt.imsave('c_plt.png', c.astype(np.uint8))
#PIL
from PIL import Image
image = Image.fromarray(c.astype(np.uint8))
image.save('c_pil.png')
#CV2, OpenCV
import cv2
cv2.imwrite('c_cv2.png', cv2.cvtColor(c, cv2.COLOR_RGB2BGR))
With pygame
so this should work as I tested (you have to have pygame installed if you do not have pygame install it by using pip -> pip install pygame (that sometimes does not work so in that case you will have to download the wheel or sth but that you can look up on google)):
import pygame
pygame.init()
win = pygame.display.set_mode((128, 128))
pygame.surfarray.blit_array(win, yourarray)
pygame.display.update()
pygame.image.save(win, 'yourfilename.png')
just remember to change display width and height according to your array
here is an example, run this code:
import pygame
from numpy import zeros
pygame.init()
win = pygame.display.set_mode((128, 128))
striped = zeros((128, 128, 3))
striped[:] = (255, 0, 0)
striped[:, ::3] = (0, 255, 255)
pygame.surfarray.blit_array(win, striped)
pygame.display.update()
pygame.image.save(win, 'yourfilename.png')
I attach an simple routine to convert a npy to an image.
from PIL import Image
import matplotlib
img = np.load('flair1_slice75.npy')
matplotlib.image.imsave("G1_flair_75.jpeg", img)
You can use this code for converting your Npy data into an image:
from PIL import Image
import numpy as np
data = np.load('/kaggle/input/objects-dataset/nmbu.npy')
im = Image.fromarray(data, 'RGB')
im.save("your_file.jpeg")

Categories