Drawing multiple Images to a tiff file in python - python

I have same size of multiple images and I want to draw those images on a tiff file in such a way that there should be less than 5 elements in a row with some x distance (horizontally along the row) between its centres and y distance (vertically along the column) The images are stored in a folder, the program should read images and draw images on tiff file.
I found this as somewhat useful (and nearer to what i require) http://www.astrobetter.com/plotting-to-a-file-in-python/ But it is plotting a graph to file. I want to put images to my tiff file
How should I proceed?

This is what you describe, I think. Here is the image, you can have many of them as long as they're all the same size, configure the values on the images list in the code to change this.
and this is the output of the program:
and here is the code:
import Image
images = ['image.jpg','image.jpg','image.jpg','image.jpg','image.jpg','image.jpg','image.jpg']
hsize = min(5,len(images))
vsize = (len(images)/5) + 1
print hsize,vsize
vspace = 10
hspace = 10
(h,w) = Image.open(images[0]).size
im = Image.new('RGB',((hsize*(h+hspace)),(vsize*(w+vspace)) ))
for i,filename in enumerate(images):
imin = Image.open(filename).convert('RGB')
xpos = i % hsize
ypos = i / hsize
print xpos,ypos
im.paste(imin,(xpos*(h+hspace),ypos*(w+vspace)))
im.save('output.jpg')

Related

Python collage of four image together

I am trying to combine 4 images, image 1 on top left, image 2 on top right, image 3 on bottom left and image 4 on bottom right. However, my images are different sizes and not sure how to resize the images to same size. I am pretty new to Python and this is my first time using PIL.
I have this so far (after opening the images)
img1 = img1.resize(img2.size)
img1 = img1.resize(img3.size)
img1 = img1.resize(img4.size)
This shall suffice your basic requirement.
This shall suffice your basic requirement.
Steps:
Images are read and stored to list of arrays using io.imread(img) in
a list comprehension.
We resize images to custom height and width.You can change IMAGE_WIDTH,IMAGE_HEIGHT as per your need with respect
to the input image size.
You just have to pass the location of n
images (n=4 for your case) to the function.
If you are
passing more than 2 images (for your case 4), it will work create 2
rows of images. In the top row, images in the first half of the list
are stacked and the remaining ones are placed in bottom row using
hconcat().
The two rows are stacked vertically using vconcat().
Finally, we convert the result to RGB image using
image.convert("RGB") and is saved using image.save().
The code:
import cv2
from PIL import Image
from skimage import io
IMAGE_WIDTH = 1920
IMAGE_HEIGHT = 1080
def create_collage(images):
images = [io.imread(img) for img in images]
images = [cv2.resize(image, (IMAGE_WIDTH, IMAGE_HEIGHT)) for image in images]
if len(images) > 2:
half = len(images) // 2
h1 = cv2.hconcat(images[:half])
h2 = cv2.hconcat(images[half:])
concat_images = cv2.vconcat([h1, h2])
else:
concat_images = cv2.hconcat(images)
image = Image.fromarray(concat_images)
# Image path
image_name = "result.jpg"
image = image.convert("RGB")
image.save(f"{image_name}")
return image_name
images=["image1.png","image2.png","image3.png","image4.png"]
#image1 on top left, image2 on top right, image3 on bottom left,image4 on bottom right
create_collage(images)
To create advanced college make you can look into this:
https://codereview.stackexchange.com/questions/275727/python-3-script-to-make-photo-collages

Downscaling a tiff image by aggregating 5x5 pixels based on stats

How to downscale a tiff image of 10m resolution and create a new image of 50m where each pixel is stats from the first image?
The initial tiff image is a binary classification map - meaning each pixel (10m) belongs either to class "water" (value =0) or class "ice" (value=1).
I would like to create a new image, where each pixel is the percentage of water in a 5 x 5 block of the initial map, meaning each pixel of the new image will have a 50 m resolution and represents the ratio or percentage of "water" pixel on every 5x5 pixel of the former map. You can see the example here: Example
Here is an image sample (can be downloaded from google drive):
https://drive.google.com/uc?export=download&id=19hWQODERRsvoESiUZuL0GQHg4Mz4RbXj
Your image is saved in a rather odd format, using a 32-bit float to represent just two classes of data which could be represented in a single bit, so I converted it to PNG with ImageMagick using:
magick YOURIMAGE.TIF -alpha off image.png
Many Python libraries will stutter on your actual TIFF so maybe think about using a different way of writing it.
Once that is done, the code might look something like this:
#!/usr/bin/env python3
from PIL import Image
import numpy as np
# Set size of tiles for subsampling
tileX = tileY = 5
# Open image and convert to greyscale and thence to Numpy array
im = Image.open('image.png').convert('L')
na = np.array(im)
# Round height and width down to next lower multiple of tile sizes
h = (na.shape[0] // tileY) * tileY
w = (na.shape[1] // tileX) * tileX
# Create empty output array to fill
res = np.empty((h//tileY,w//tileX), np.uint8)
pxPerTile = tileX * tileY
for yoffset in range(0,h,tileY):
for xoffset in range(0,w,tileX):
# Count ice pixels in this 5x5 tile
nonZero = np.count_nonzero(na[yoffset:yoffset+tileY, xoffset:xoffset+tileX])
percent = int((100.0 * (pxPerTile - nonZero))/pxPerTile)
res[yoffset//tileY, xoffset//tileX] = percent
# Make Numpy array back into PIL Image and save
Image.fromarray(res.astype(np.uint8)).save('result.png')
On reflection, you can probably do it faster and more simply with cv2.resize() and a decimation of 0.2 on both axes and interpolation cv2.INTER_AREA
I did a version in pyvips:
#!/usr/bin/python3
import sys
import pyvips
image = pyvips.Image.new_from_file(sys.argv[1])
# label (0 == water, 1 == ice) is in the first band
label = image[0]
# average 5x5 areas
label = label.shrink(5, 5)
# turn into a percentage of water
water_percent = 100 * (1 - label)
# ... and save
water_percent.write_to_file(sys.argv[2])
I can run it on your test image like this:
$ ./average.py ~/pics/meltPondClassifiedAndS12.tif x.png
To make this (rather dark) output:

Create automatic way to convert whole image dataset into annotation file(.xml file)

I have a dataset which is already cropped detecting the roof. (1 image has only 1 roof)
ex:-
I'm familiar with labelImg tool but it take time.
Is there any way to convert every image file from folder into annotation file like image size as (xmin,ymin,xmax,ymax) and save in PascalVOC format .xml file.
If the images are already cropped, then you should be able to get your bounding boxes by inspecting the images.
from PIL import Image
paths_of_images_in_training_directories = #recursive directory walk of training dir
for training_image in paths_of_images_in_training_directories:
img = Image.open(training_image)
image_w, image_h = img.size
# Determine xmin,ymin,xmax,ymax or annotations
xmin = 0
ymin = 0
xmax = image_w
ymax = image_h
# ...write annotations to .xml file

Auto-cropping images with PIL

I have folder full of images with each image containing at least 4 smaller images. I would to know how I can cut the smaller images out using Python PIL so that they will all exist as independent image files. fortunately there is one constant, the background is either white or black so what I'm guessing I need is a way to the cut these images out by searching for rows or preferably columns which are entirely black or entirely white, Here is an example image:
From the image above, there would be 10 separate images, each containing a number. Thanks in advance.
EDIT: I have another sample image that is more realistic in the sense that the backgrounds of some of the smaller images are the same colour as the background of the image they are contained in. e.g.
The output of which being 13 separate images, each containng 1 letter
Using scipy.ndimage for labeling:
import numpy as np
import scipy.ndimage as ndi
import Image
THRESHOLD = 100
MIN_SHAPE = np.asarray((5, 5))
filename = "eQ9ts.jpg"
im = np.asarray(Image.open(filename))
gray = im.sum(axis=-1)
bw = gray > THRESHOLD
label, n = ndi.label(bw)
indices = [np.where(label == ind) for ind in xrange(1, n)]
slices = [[slice(ind[i].min(), ind[i].max()) for i in (0, 1)] + [slice(None)]
for ind in indices]
images = [im[s] for s in slices]
# filter out small images
images = [im for im in images if not np.any(np.asarray(im.shape[:-1]) < MIN_SHAPE)]

How do you merge images into a canvas using PIL/Pillow?

I'm not familiar with PIL, but I know it's very easy to put a bunch of images into a grid in ImageMagick.
How do I, for example, put 16 images into a 4×4 grid where I can specify the gap between rows and columns?
This is easy to do in PIL too. Create an empty image and just paste in the images you want at whatever positions you need using paste. Here's a quick example:
import Image
#opens an image:
im = Image.open("1_tree.jpg")
#creates a new empty image, RGB mode, and size 400 by 400.
new_im = Image.new('RGB', (400,400))
#Here I resize my opened image, so it is no bigger than 100,100
im.thumbnail((100,100))
#Iterate through a 4 by 4 grid with 100 spacing, to place my image
for i in xrange(0,500,100):
for j in xrange(0,500,100):
#I change brightness of the images, just to emphasise they are unique copies.
im=Image.eval(im,lambda x: x+(i+j)/30)
#paste the image at location i,j:
new_im.paste(im, (i,j))
new_im.show()
Expanding on the great answer by fraxel, I wrote a program which takes in a folder of (.png) images, a number of pixels for the width of the collage, and the number of pictures per row, and does all the calculations for you.
#Evan Russenberger-Rosica
#Create a Grid/Matrix of Images
import PIL, os, glob
from PIL import Image
from math import ceil, floor
PATH = r"C:\Users\path\to\images"
frame_width = 1920
images_per_row = 5
padding = 2
os.chdir(PATH)
images = glob.glob("*.png")
images = images[:30] #get the first 30 images
img_width, img_height = Image.open(images[0]).size
sf = (frame_width-(images_per_row-1)*padding)/(images_per_row*img_width) #scaling factor
scaled_img_width = ceil(img_width*sf) #s
scaled_img_height = ceil(img_height*sf)
number_of_rows = ceil(len(images)/images_per_row)
frame_height = ceil(sf*img_height*number_of_rows)
new_im = Image.new('RGB', (frame_width, frame_height))
i,j=0,0
for num, im in enumerate(images):
if num%images_per_row==0:
i=0
im = Image.open(im)
#Here I resize my opened image, so it is no bigger than 100,100
im.thumbnail((scaled_img_width,scaled_img_height))
#Iterate through a 4 by 4 grid with 100 spacing, to place my image
y_cord = (j//images_per_row)*scaled_img_height
new_im.paste(im, (i,y_cord))
print(i, y_cord)
i=(i+scaled_img_width)+padding
j+=1
new_im.show()
new_im.save("out.jpg", "JPEG", quality=80, optimize=True, progressive=True)

Categories

Resources