I want to convert an image so I can read it better using pyocr & tesseract.
The Command line I want to convert to python is :
convert pic.png -background white -flatten -resize 300% pic_2.png
Using python Wand I managed to resize it but I don't know how to do the flattend and the white background
My try :
from wand.image import Image
with Image(filename='pic.png') as image:
image.resize(270, 33) #Can I use 300% directly ?
image.save(filename='pic2.png')
Please help
Edit, Here is the image to make tests on :
For resize & background. Use the following, and note that you'll need to calculate the 300% yourself.
from wand.image import Image
from wand.color import Color
with Image(filename="pic.png") as img:
# -resize 300%
scaler = 3
img.resize(img.width * scaler, img.height * scaler)
# -background white
img.background_color = Color("white")
img.save(filename="pic2.png")
Unfortunately the c method MagickMergeImageLayers has yet to be implemented. You should author an enhancement request with the development team.
Update
If you want to remove the transparency, just disable the alpha channel
from wand.image import Image
with Image(filename="pic.png") as img:
# Remove alpha
img.alpha_channel = False
img.save(filename="pic2.png")
Another way
It might just be easier to create a new image with the same dimensions as the first, and just composite the source image over the new one.
from wand.image import Image
from wand.color import Color
with Image(filename="pic.png") as img:
with Image(width=img.width, height=img.height, background=Color("white")) as bg:
bg.composite(img,0,0)
# -resize 300%
scaler = 3
bg.resize(img.width * scaler, img.height * scaler)
bg.save(filename="pic2.png")
Related
I wish to expand an image, so I can write something at the black expanded space under the original image, but it doesn't work.
I can't expand a black space and add it to the image, neither can write at a specific place
I'm new to the Pillow library, can anyone help?
You could do something like this:
read the image
create a new image (black by default) with the desired size
get data of the input image and put it down on the new one
from PIL import Image
HEIGH_OF_THE_BLACK_AREA = 100
with Image.open('image.jpg') as im:
new_im = Image.new(im.mode, size = (im.size[0], im.size[1] + HEIGH_OF_THE_BLACK_AREA))
new_im.putdata(im.getdata())
new_im.save('out.jpg')
How can I convert a non-transparent PNG file into a transparent GIF file with PIL?
I need it for my turtle-graphics game. I can only seem to transparentize a PNG file, not a GIF file.
It's not obvious, to me at least, how you are supposed to do that! This may be an unnecessary work-around for a problem that doesn't exist because I don't know something about how PIL works internally.
Anyway, I messed around with it long enough using this input image:
#!/usr/bin/env python3
from PIL import Image, ImageDraw, ImageOps
# Open PNG image and ensure no alpha channel
im = Image.open('start.png').convert('RGB')
# Draw alpha layer - black square with white circle
alpha = Image.new('L', (100,100), 0)
ImageDraw.Draw(alpha).ellipse((10,10,90,90), fill=255)
# Add our lovely new alpha layer to image
im.putalpha(alpha)
# Save result as PNG and GIF
im.save('result.png')
im.save('unhappy.gif')
When I get to here, the PNG works and the GIF is "unhappy".
PNG below:
"Unhappy" GIF below:
Here is how I fixed up the GIF:
# Extract the alpha channel
alpha = im.split()[3]
# Palettize original image leaving last colour free for transparency index
im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
# Put 255 everywhere in image where we want transparency
im.paste(255, ImageOps.invert(alpha))
im.save('result.gif', transparency=255)
Keywords: Python, image processing, PIL, Pillow, GIF, transparency, alpha, preserve, transparent index.
I am aware of Replace a color using Wand and Change color of specific pixels [Wand] but both of these use a line like
draw.color(192,84,'replace')
In which you need to pass the location of a pixel of the relevant color. What if you know the color you want to replace but not its location? I want to replace the color of pixels in an image without passing a reference to the location of a pixel of that color. Do you really have to scan the entire image looking for something you already know is there?
The imagemagick equivalent would be
convert balloon.gif -fill white -opaque blue balloon_white.gif
If you want to match -opaque functionality, then you'll need to implement the MagickOpaquePaintImage C method.
import ctypes
from wand.api import library
from wand.image import Image
from wand.color import Color
from wand.compat import nested
# Map C-API to Python
library.MagickOpaquePaintImage.argtypes = (ctypes.c_void_p, # Wand
ctypes.c_void_p, # target
ctypes.c_void_p, # fill
ctypes.c_double, # fuzz
ctypes.c_bool) # invert
with Image(filename='rose:') as img:
with nested(Color('#E93A43'), Color('ORANGE')) as (target, fill):
library.MagickOpaquePaintImage(img.wand,
target.resource,
fill.resource,
img.quantum_range * 0.10, # -fuzz 10%
False)
img.save(filename='output.png')
Since wand 0.5.4 the method opaque_paint is available so the clever hack #emcconville proposed is not required anymore. You can do just:
from wand.image import Image
with Image(filename='rose:') as im:
im.opaque_paint(target='#E93A43', fill='Orange', fuzz=0.10)
im.save(filename='output.png')
I'm trying to use this this approach to add a semi-transparent polygon to an image. The problem is the image is a JPEG. I know that JPEGs don't have an alpha channel, so I was hoping there was a way I could have PIL take in a JPEG, convert it to a form which has an alpha channel, add the semi-transparent mask, then merge the mask with the image and convert it back into a JPEG for saving. Can PIL accomplish this? If not, how else might I go about doing this? Thanks!
That's easy. Just paste the jpeg into a new rgba Image():
#!/usr/bin/env python3
from PIL import Image
from PIL import ImageDraw
im = Image.open("existing.jpg")
logo = Image.open("python-32.png")
back = Image.new('RGBA', im.size)
back.paste(im)
poly = Image.new('RGBA', (512,512))
pdraw = ImageDraw.Draw(poly)
pdraw.polygon([(128,128),(384,384),(128,384),(384,128)],
fill=(255,255,255,127),outline=(255,255,255,255))
back.paste(poly, (0,0), mask=poly)
back.paste(logo, (im.size[0]-logo.size[0], im.size[1]-logo.size[1]), mask=logo)
back.show()
This additionally adds a png (with transparency) to the image.
When loading a png image with PIL and OpenCV, there is a color shift. Black and white remain the same, but brown gets changed to blue.
I can't post the image because this site does not allow newbies to post images.
The code is written as below rather than use cv.LoadImageM, because in the real case the raw image is received over tcp.
Here is the code:
#! /usr/bin/env python
import sys
import cv
import cv2
import numpy as np
import Image
from cStringIO import StringIO
if __name__ == "__main__":
# load raw image from file
f = open('frame_in.png', "rb")
rawImage = f.read()
f.close()
#convert to mat
pilImage = Image.open(StringIO(rawImage));
npImage = np.array(pilImage)
cvImage = cv.fromarray(npImage)
#show it
cv.NamedWindow('display')
cv.MoveWindow('display', 10, 10)
cv.ShowImage('display', cvImage)
cv. WaitKey(0)
cv.SaveImage('frame_out.png', cvImage)
How can the color shift be fixed?
OpenCV's images have color channels arranged in the order BGR whereas PIL's is RGB. You will need to switch the channels like so:
import PIL.Image
import cv2
...
image = np.array(pilImage) # Convert PIL Image to numpy/OpenCV image representation
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) # You can use cv2.COLOR_RGBA2BGRA if you are sure you have an alpha channel. You will only have alpha channel if your image format supports transparency.
...
#Krish: Thanks for pointing out the bug. I didn't have time to test the code the last time.
Hope this helps.
Change
pilImage = Image.open(StringIO(rawImage))
to
pilImage = Image.open(StringIO(rawImage)).convert("RGB")
Light alchemist's answer did not work, but it did explain the issue. Wouldn't the reverse be screwed up by the Apha channel, i.e. it changes BRGA to AGRB. I would think Froyo's answer would solve it, but it did not change the displayed image at all. What did work was reversing the colors in OpenCV. I'm too much of a newbie to know why. They seem equivalent to me. Reversing the colors in numpy would be preferred as additional processing is planned in numpy. But thanks for the help, the answers steered me in the right direction.
pilImage = Image.open(StringIO(rawImage));
bgrImage = np.array(pilImage)
cvBgrImage = cv.fromarray(bgrImage)
# Reverse BGR
cvRgbImage = cv.CreateImage(cv.GetSize(cvBgrImage),8,3)
cv.CvtColor(cvBgrImage, cvRgbImage, cv.CV_BGR2RGB)
#show it
cv.ShowImage('display', cvRgbImage)
cv. WaitKey(30) # ms to allow display