I have the following code:
def resizeImg(img, width, height):
outerImg = img(width=width, height=height, background=Color("WHITE"))
outerImg.units='pixelsperinch'
outerImg.resolution = (300, 300)
outerImg.format = img.format.lower()
outerImg.composite_channel('undefined', img, 'over', int((width - img.width) / 2), int((height - img.height) / 2))
return outerImg
for file in os.listdir():
if os.path.splitext(file)[1] in ('.tif', '.jpeg', '.jpg'):
with Image() as img:
fname = ntpath.basename(file).split('.')[0] # BC154360-ANG
img.read(filename=file)
img.units='pixelsperinch'
img.resolution = (300, 300)
img.compression_quality = 99
img.format = 'jpg'
dim = max(img.width, img.height)
img.resize(height=dim, width=dim) # make image square
img.resize(height=1500, width=1500) # set image size to 1500x1500
img.units='pixelsperinch'
img.resolution = (72, 72)
img.save(filename = jpg_location + fname + '.jpg') # .jpg
The issue is that I am getting multiple files when I run this, and they're all slightly different. It seems as if each image has been processed differently. The "-0" image appears to be correct, as does the result when I run display(img).
Can someone explain what is going on here? Perhaps it is the result of the channel and operator parameters in the composite_channel function?
Related
I use opencv to count the number of white and black pixels of picture(I have convert them into black and white image), and everytime I run my code it return the number is 0,and the code is
output_path = "/content/drive/MyDrive/dataset_demo/result_pic"
for pic in os.listdir(output_path):
if pic.endswith('.jpg'):
image = cv2.imread(pic,cv2.IMREAD_UNCHANGED)
number_of_white_pix = np.sum(image == 255)
number_of_black_pix = np.sum(image == 0)
number_of_total = number_of_white_pix + number_of_black_pix
number_of_ratio = number_of_white_pix / number_of_black_pix
print(number_of_total)
The pic variable contains only the file name of the image, but cv2.imread needs the full path to the image in order to read it. You need to use the full path to the image when you call cv2.imread.
output_path = "/content/drive/MyDrive/dataset_demo/result_pic"
for pic in os.listdir(output_path):
if pic.endswith('.jpg'):
pic = os.path.join(output_path, pic) #full path to the image
image = cv2.imread(pic,cv2.IMREAD_UNCHANGED)
number_of_white_pix = np.sum(image == 255)
number_of_black_pix = np.sum(image == 0)
number_of_total = number_of_white_pix + number_of_black_pix
number_of_ratio = number_of_white_pix / number_of_black_pix
print(number_of_total)
When I am processing a bunch of images, on one of them I get this error
File "/home/tensorflowpython/firstmodel/yololoss.py", line 153, in data_generator
image, box = get_random_data(annotation_lines[i], input_shape, random=True)
File "/home/tensorflowpython/firstmodel/yololoss.py", line 226, in get_random_data
image = image.resize((nw,nh), Image.BICUBIC)
File "/home/tensorflowpython/kenv/lib/python3.6/site-packages/PIL/Image.py", line 1858, in resize
self.load()
File "/home/tensorflowpython/kenv/lib/python3.6/site-packages/PIL/ImageFile.py", line 247, in load
"(%d bytes not processed)" % len(b)
OSError: image file is truncated (25 bytes not processed)
I have already tried the solution suggested here but it doesn't work
my code looks like this
from PIL import Image
def get_random_data(annotation_line, input_shape, random=True, max_boxes=20, jitter=.3, hue=.1, sat=1.5, val=1.5, proc_img=True):
Image.LOAD_TRUNCATED_IMAGES = True
line = annotation_line.split()
image = Image.open(line[0])
iw, ih = image.size
h, w = input_shape
box = np.array([np.array(list(map(int,box.split(',')))) for box in line[1:]])
try:
image.load()
except IOError:
pass # You can always log it to logger
if not random:
# resize image
scale = min(w/iw, h/ih)
nw = int(iw*scale)
nh = int(ih*scale)
dx = (w-nw)//2
dy = (h-nh)//2
image_data=0
if proc_img:
image = image.resize((nw,nh), Image.BICUBIC)
new_image = Image.new('RGB', (w,h), (128,128,128))
new_image.paste(image, (dx, dy))
image_data = np.array(new_image)/255.
# correct boxes
box_data = np.zeros((max_boxes,5))
if len(box)>0:
np.random.shuffle(box)
if len(box)>max_boxes: box = box[:max_boxes]
box[:, [0,2]] = box[:, [0,2]]*scale + dx
box[:, [1,3]] = box[:, [1,3]]*scale + dy
box_data[:len(box)] = box
return image_data, box_data
# resize image
new_ar = w/h * rand(1-jitter,1+jitter)/rand(1-jitter,1+jitter)
scale = rand(.25, 2)
if new_ar < 1:
nh = int(scale*h)
nw = int(nh*new_ar)
else:
nw = int(scale*w)
nh = int(nw/new_ar)
image = image.resize((nw,nh), Image.BICUBIC) #error occurs here
The difference between my error and the previous solution is, mine says OS error and the solution is for IO error
EDIT: I have figured out the image that is causing this error, it can be downloaded from this link
I tried the solution that you linked with the truncated image and it worked. You made a slight mistake when trying to apply this solution: you have to set ImageFile.LOAD_TRUNCATED_IMAGES=True, not Image.LOAD_TRUNCATED_IMAGES.
LOAD_TRUNCATED_IMAGES does not originally exist in Image module, so when you do Image.LOAD_TRUNCATED_IMAGES=True you set a new variable which is not used by the library.
So I think you juste have to do that:
from PIL import ImageFile, Image
ImageFile.LOAD_TRUNCATED_IMAGES = True
image = Image.open("00090.jpg")
# resize now doesn't fail
image.resize((h, w), Image.BICUBIC)
I have two folders of images and I am trying to build one large image from all the slices in each folder. I need to alternate between folders to build the image. For example the first slice comes from folder 1, the second slice comes from folder 2, the third from folder 1 ect. I have the files ordered by filename in the individual folders so I am trying to iterate through the folders and add a new strip to an image. The code runs BUT it doesn't seem to be saving the composite image. I am new to PIL, so I am sure that it is something simple, but your help is appreciated. Thanks!
def merge_images(file1, file2):
"""Merge two images into one, displayed above and below
:param file1: path to first image file
:param file2: path to second image file
:return: the merged Image object
"""
if file1.startswith('.'):
return None
image1 = Image.open(file1)
image2 = Image.open(file2)
(width1, height1) = image1.size
(width2, height2) = image2.size
result_width = width1 + width2
result_height = max(height1, height2)
result = Image.new('RGB', (result_width, result_height))
result.paste(im=image1, box=(0, 0))
result.paste(im=image2, box=(0, height1))
return result
imageCounter = 0
firstPass = True
compImage = Image.new('RGBA', img.size, (0,0,0,0))
for i in range(len(boundingBoxes)+1):
if firstPass:
compImage = merge_images('./image_processing/'+ os.listdir('./image_processing/')[imageCounter],
'./img_patches/outputs/'+os.listdir('./img_patches/outputs/')[imageCounter])
if compImage is not None:
firstPass = False
compImage.save('./image_processing/compImage.jpg')
else:
compImage = merge_images('./image_processing/compImage.jpg','./image_processing/'+ os.listdir('./image_processing/')[imageCounter])
compImage.save('./image_processing/compImage.jpg')
compImage = merge_images('./image_processing/compImage.jpg','./img_patches/outputs/'+ os.listdir('./img_patches/outputs/')[imageCounter])
compImage.save('./image_processing/compImage.jpg')
imageCounter = imageCounter + 1
You have to tell PIL to save the images:
for i in range(len(boundingBoxes)+1):
if firstPass:
compImage = merge_images('./image_processing/'+ os.listdir('./image_processing/')[imageCounter],
'./img_patches/outputs/'+os.listdir('./img_patches/outputs/')[imageCounter])
compImage.save(open('output/{}.png'.format(imageCounter), 'w'))
I am fairly new to Python and have a difficult Problem to solve:
Here is what I am trying to do -->
I have a Folder (path known) with 1 - x picture files (.jpg) in it, whereas x can be as high as 1000
These picture files should be stiched together (one on top of the other)
To do so I want Python to assign a variable to each Picture file in the known folder and then create a loop which stiches these variable-stored pictures together and outputs it as 1 picture (.jpg)
Here is what I have coded so far:
from PIL import Image
import glob
#The following GLOB part doesn't work, I tried to make a List with all the
#files (.jpg) inside the main directory
#image_list = []
#for filename in glob.glob('*.jpg'):
# test = Image.open(filename)
# image_list.append(test)
img1 = Image.open("img1.jpg")
img2 = Image.open("img2.jpg")
def merge_images(img1, img2):
(width1, height1) = img1.size
(width2, height2) = img2.size
result_width = max(width1, width2)
result_height = height1 + height2
result = Image.new('RGB', (result_width, result_height))
result.paste(im=img2, box=(0,0))
result.paste(im=img1, box=(0,height1-2890))
return result
merged = merge_images(img1, img2)
merged.save("test.jpg")
What this does is to assign img1.jpg and img2.jpg to a variable and then stack them on top of oneanother and save this stacked picture as "test.jpg". Where do I go from here if I want to assign many pictures (.jpg) to variables and stack them on top of each other without typing a line of code for each new picture (see description further up?)
Thanks a lot for your help!
Chris
If you start with a 0x0 image, you can stack further images onto it like this:
stacked_img = Image.new('RGB', (0, 0))
for filename in glob.glob('*.jpg'):
stacked_img = merge_images(stacked_img, Image.open(filename))
stacked_img.save('stacked.jpg')
You might also like to change the height1-2890 to height2 in the merge_images() function if you are trying to stack the second image below the first image, i.e.
result.paste(im=img1, box=(0,height2))
Why not use a container such as a list?
images = [Image.open(img_name) for img_name in os.listdir(my_folder) if img_name.endswith('.jpg')
def merge_images(list_images):
result_width = max(img.size[0] for img in images)
result_height = sum(img.size[1] for img in images)
result = Image.new('RGB', (result_width, result_height))
for idx, img in enumerate(list_images):
result.paste(im=img, box=(0,list_images[0].size[1]-idx*2890))
See Data Structures for more information.
If performance is important, consider using map instead of a loop.
this is my code in which I implemented your approach. As a result, I am getting an image where 2 of the 4 images are displayed and the rest of the image is black. In the source directory I have 4 images (img1.jpg - img4.jpg)
from PIL import Image
import glob
stacked_img = Image.new('RGB', (0,0))
def merge_images(img1, img2):
(width1, height1) = img1.size
(width2, height2) = img2.size
result_width = max(width1, width2)
result_height = height1 + height2
result = Image.new('RGB', (result_width, result_height))
result.paste(im=img2, box=(0,0))
result.paste(im=img1, box=(0,height1))
return result
for filename in glob.glob('*.jpg'):
stacked_img = merge_images(stacked_img, Image.open(filename))
stacked_img.save('stacked.jpg')
I'm trying to find a way to watermark a gif image, below is my code:
img = Image.open("my.gif")
watermark = Image.open("watermark.gif")
img.paste(watermark, (1, 1))
img.save("out.gif")
File: my.gif:
File: watermark.gif:
the output "out.gif" is no longer animated, it shows one frame with the watermark:
I know that PIL supports the GIF format, so I must be doing something wrong. All help is appreciated.
Animated GIFs are actually a sequence of images with rules and times for switching between them you need to modify all of them and output all of them - you can use images2gif for this - or you can do a lot of work yourself.
Example of using images2gif, after downloading from the above link:
from PIL import Image
import images2gif as i2g
images = i2g.readGif('Animated.gif', False)
watermark = Image.open("Watermark.gif")
for i in images: i.paste(watermark, (1, 1))
i2g.writeGif('Out.gif', images, 0.5) # You may wish to play with the timing, etc.
exit()
And the results:
Images2gif not working on Python 3. I checked PIL doc, it support reading GIF image, but when saved, the image is not animated. I have a requirement to watermark images uploaded by our app's user, the code I've already done as following. It worked for none GIF images.
def watermark(fp, text, position=None, font=None, quality=85):
if isinstance(fp, bytes):
fp = BytesIO(fp)
im = Image.open(fp)
water_im = Image.new("RGBA", im.size)
water_draw = ImageDraw.ImageDraw(water_im)
if isinstance(font, str):
font = ImageFont.truetype(font, 10 + int(im.size[0] / 100))
if not position:
water_size = water_draw.textsize(text, font=font)
position = (im.size[0] - water_size[0] * 1.05,
im.size[1] - water_size[1] * 1.2)
water_draw.text(position, text, font=font)
water_mask = water_im.convert("L").point(lambda x: min(x, 160))
water_im.putalpha(water_mask)
if im.format == 'GIF':
for frame in ImageSequence.Iterator(im):
frame.paste(water_im, None, water_im)
else:
im.paste(water_im, None, water_im)
out = BytesIO()
im.save(out, im.format, quality=quality, **im.info)
return out.getvalue()