I have an image (a captcha) that I download from the web.
When I loaded to opencv it seems to loose its properties or simply mixes the transparent background with the dark/black colors:
Currently the code does nothing but loading a writing again:
captchaImg = cv2.imread('captcha1.png')
cv2.imwrite("captcha2.png", captchaImg)
I have tried loading also with options 0, 1, 2, 3 but the result is the same.
Using the provided constants might help. I do the equivalent of
captchaImg = cv2.imread('captcha1.png', cv2.IMREAD_UNCHANGED)
which reads the alpha channel (if there is one). The REPL says that cv2.IMREAD_UNCHANGED is -1
Well this is a problem with opencv and it has a solution with opencv but it is kind of complex so I went on and use another libary (PIL) that I was going to use any way.
Basically what you do is put a white image behind the transparent one an with that you solve the problem.
The code is the following:
image = Image.open("captcha1.png")
image.convert("RGBA")
canvas = Image.new('RGBA', image.size, (255,255,255,255)) # Empty canvas colour (r,g,b,a)
canvas.paste(image, mask=image) # Paste the image onto the canvas, using it's alpha channel as mask
canvas.save("captcha1.png", format="PNG")
I hope it helps someone with the same problem.
Related
I am currently working on a discord bot with Pycord. I am working on adding support for GIF images on the currently existing image commands, and I need the color of the pixels. When I try to get the color of an exact point in PIL/Pillow, I get a number representing the color of the pixel in the GIF color table, which is not what I want. Even when I convert the image to RGBA, I still get only the index, nothing else. When I google it, all I see is multitudes of this same method that I tried.
Here is a basic program to demonstrate what I have tried:
from io import BytesIO as toimg
from PIL import Image, ImageFont, ImageDraw, ImageOps, ImageSequence
#reqdata is gif data from a url
imggif = Image.open(toimg(reqdata.content))
for frame in ImageSequence.Iterator(imggif):
img = frame.convert("RGBA")
img = img.convert("RGBA") # might not need this due to the line above but idk
img = ImageOps.grayscale(img) # this line was not here before, edited it in.
width, height = img.size
for y in range(height):
for x in range(width):
print(img.getpixel((x,y))) # this prints out only one number, i need an RGBA value (4 numbers)
If anyone can help, that would be very appreciated!
Edit: I found out the solution and I realized that it was not the frame itself, but instead it was because I grayscaled the image after converting it. The program was created based on what I thought was the mistake, and I didn't even check it! This was nowhere in the question and i apologize for not thinking to look at such a simple thing before posting this question. I had to convert back to RGBA after grayscaling the image. :(
Edit 2: I am just now realizing that this is going to be my very last question, and that I should have looked further to realize my incredibly simple mistake before wasting my last chance on this site i will ever have. It's for the better, I'm a dumbass who is unable to realize such simple things. I will not be and have not been needed on this site.
Try
r, g, b, a = img.getpixel((x, y))
I tested this and it works for me. Based on [this post].
(Get pixel's RGB using PIL)
Edit: another approach that has worked for me in the past is to use pixels = img.load() and index a pixel like pixels[x, y]
This worked for me
from PIL import Image
red_image = Image.open("red.png")
red_image_rgb = red_image.convert("RGB")
rgb_pixel_value = red_image_rgb.getpixel((10,15))
print(rgb_pixel_value) #Prints (255, 0, 0)
Okay, first thing first. This is a near duplicate of this question.
However, the issue I am facing is slightly different in a critical way.
In my application, I read a generic file name in, load said image, and display it. Where it gets tricky is I have overlay the appearance of being 'highlighted'. To do this, I was using the Image.blend() function, and blending it with a straight yellow image.
However, when dealing with blend, I was fighting the error that the two images are not compatible to be blended. To solve this, I opened the sample image I had in paint, and just pasted yellow over the whole thing, and saved it as a copy.
It just occurred to me that this will fail when a different type of image is read in by file name. Remember this needs to be generic.
So my question is: Instead of making a copy of the image manually, can I get python to generate one by copying the image and modifying it so it is solid yellow? Note: I do not need to save it after, so just making it happen is enough.
Unfortunately, I am not allowed to share my code, but hopefully the following will give an idea of what I need:
from PIL import Image
desiredWidth = 800
desiredHeight = 600
primaryImage = Image.open("first.jpg").resize((desiredWidth, desiredHeight), Image.ANTIALIAS)
# This is the thing I need fixed:
highlightImage = Image.open("highlight.jpg").resize((desiredWidth, desiredHeight), Image.ANTIALIAS)
toDisplay = Image.blend(primaryImage, highlightImage, 0.3)
Thanks to anyone who can help.
Sounds like you want to make a new image:
fill_color = (255,255,0) #define the colour as (R,G,B) tuple
highlightImage = Image.new(primaryImage.mode, #same mode as the primary
primaryImage.size, #same size as the primary
fill_color)#and the colour defined above
this creates a new image with the same mode and size as the already opened image, but with a solid colour. Cheers.
Also if you are using Pillow instead of original PIL you can even get the color by name:
from PIL.ImageColor import getcolor
overlay = 'yellow'
fill_color = getcolor(overlay, primaryImage.mode)
So I have implemented the following screenshot functionality into my game just to log progress and stuff like that. This is my code:
pygame.image.save(screen, save_file)
Pretty basic. I recently upgraded to python 3.3 and have since been having the issue of distorted colors using this function. Here is what I mean:
Distorted Color:
So it looks quite nice, but it isn't how it supposed to be. This is the actual image:
Is this a known issue or is it just me? Are there any fixes to it or is it just a broken function at the moment. I am using pygame 1.9.2pre and I am assuming it is just a bug with the pre release but I was having issues using any other versions of pygame with python 3.3.
Some users have reported difficulty with saving images as pngs:
I only get .tga files even when I specify .png. Very frustrating.
If you use .PNG (uppercase), it will result in an invalid file (at least on my win32). Use .png (lowercase) instead.
PNG does not seem to work, I am able to get a preview of it in Thunar, but everywhere else It says that it is not a valid PNG.
Saving in a different format may be helpful. For example, BMP is a simple format, so it's unlikely that Pygame's implementation will be buggy.
If you really want to save as PNG, you can reverse the distortion by swapping the red channel with the green one. This is fairly easy. For example, using PIL:
from PIL import Image
im = Image.open("screenshot.png")
width, height = im.size
pix = im.load()
for i in range(width):
for j in range(height):
r,g,b = pix[i,j]
pix[i,j] = (g,r,b)
im.save("output.png")
Or you can save as BMP and convert to PNG after the fact:
from PIL import Image
im = Image.open("screenshot.bmp")
im.save("screenshot.png")
for future reference, this trick worked for me:
from PIL import Image
imgdata = pygame.surfarray.array3d(screen).transpose([1,0,2])[:,:,::-1]
Image.fromarray(imgdata).save('output.png')
This is my issue:
import Image
im = Image.open("1.png")
im.show()
print im.mode
im.convert("RGBA").save("2.png")
Well, with my image you can see the difference.
My question is: how do I convert it properly?
Image:
Result:
NOTE: The original image has a semi-transparent glow, the result has a solid green "glow"
This issue was reported here:
https://bitbucket.org/effbot/pil-2009-raclette/issue/8/corrupting-images-in-palette-mode
In March 2012, a comment says it's now fixed in development version of PIL. The most recent released version is 1.1.7, so the fix won't be available until 1.2 comes out. PIL updates very slowly, so don't expect this to come out soon.
Unfortunately your PNG image is a type that PIL doesn't handle very well - a paletted image with an alpha channel. When you open the image, the alpha is thrown away and there's no way to get it back.
This is different from the usual palette transparency where one index of the palette is used to denote fully transparent pixels.
You could use scipy.misc.imread:
img = scipy.misc.imread(filename, mode='RGBA')
img = Image.fromarray(img)
Your problem is that you do not provide info about what PIL should use as source of ALPHA channel.
PIL will not on its own add transparency to your image.
What part of your image you want to be transparent?
I create an image with PIL:
I need to fill in the empty space (depicted as black). I could easily fill it with a static color, but what I'd like to do is fill the pixels in with nearby colors. For example, the first pixel after the border might be a Gaussian blur of the filled-in pixels. Or perhaps a push-pull type algorithm described in The Lumigraph, Gortler, et al..
I need something that is not too slow because I have to run this on many images. I have access to other libraries, like numpy, and you can assume that I know the borders or a mask of the outside region or inside region. Any suggestions on how to approach this?
UPDATE:
As suggested by belisarius, opencv's inpaint method is perfect for this. Here's some python code that uses opencv to achieve what I wanted:
import Image, ImageDraw, cv
im = Image.open("u7XVL.png")
pix = im.load()
#create a mask of the background colors
# this is slow, but easy for example purposes
mask = Image.new('L', im.size)
maskdraw = ImageDraw.Draw(mask)
for x in range(im.size[0]):
for y in range(im.size[1]):
if pix[(x,y)] == (0,0,0):
maskdraw.point((x,y), 255)
#convert image and mask to opencv format
cv_im = cv.CreateImageHeader(im.size, cv.IPL_DEPTH_8U, 3)
cv.SetData(cv_im, im.tostring())
cv_mask = cv.CreateImageHeader(mask.size, cv.IPL_DEPTH_8U, 1)
cv.SetData(cv_mask, mask.tostring())
#do the inpainting
cv_painted_im = cv.CloneImage(cv_im)
cv.Inpaint(cv_im, cv_mask, cv_painted_im, 3, cv.CV_INPAINT_NS)
#convert back to PIL
painted_im = Image.fromstring("RGB", cv.GetSize(cv_painted_im), cv_painted_im.tostring())
painted_im.show()
And the resulting image:
A method with nice results is the Navier-Stokes Image Restoration. I know OpenCV has it, don't know about PIL.
Your example:
I did it with Mathematica.
Edit
As per your reuquest, the code is:
i = Import["http://i.stack.imgur.com/uEPqc.png"];
Inpaint[i, ColorNegate#Binarize#i, Method -> "NavierStokes"]
The ColorNegate# ... part creates the replacement mask.
The filling is done with just the Inpaint[] command.
Depending on how you're deploying this application, another option might be to use the Gimp's python interface to do the image manipulation.
The doc page I linked to is oriented more towards writing GIMP plugins in python, rather than interacting with a background gimp instance from a python app, but I'm pretty sure that's also possible (it's been a while since I played with the gimp/python interface, I'm a little hazy).
You can also create the mask with the function CreateImage(), for instance:
inpaint_mask = cv.CreateImage(cv.GetSize(im), 8, 1)