I've got a function that takes an image and adjusts all of the RGB values by a given amount:
def colour(self,img,col):
img = self.my_image.copy()
col = (col[0],col[1],col[2],0)
img.fill(col, None, pygame.BLEND_RGBA_ADD)
return img
I want to apply this to a partially transparent image. But when I apply this to the image, the transparent pixels become coloured. I want these pixels to stay transparent, but any opaque pixels to be coloured as normal. Is there any way I can do this, without having to loop through every pixel and check if each one is transparent before adjusting it? Thanks
fill treats the color to be solid. You have to use blit.
Create a transparent image the size of the source image and fill it with the color. Finally, mix both images:
def colour(self, img, col):
img = self.my_image.copy()
color_img = pygame.Surface(img.get_size(), pygame.SRCALPHA)
color_img.fill((col[0], col[1], col[2], 0))
img.blit(color_img, (0, 0), special_flags = pygame.BLEND_RGBA_ADD)
return img
See also Is it possible to change sprite colours in Pygame?
Related
I am currently trying to use an RGBA image to 'punch' out a hole in another RGBA image but all my current attempts have failed to maintain the original transparency. Once I apply an alpha channel using putalpha it will replace the original alpha channel completely and turn previously transparent pixels back to their original colors.
I am trying to perform a "putalpha" on only the pixels with 100% transparency.
In the photos below I attempt to overlap an 'inverted transparency' alpha channel on top of my Circle to perform the 'punch out'. Instead of only applying the transparent pixels it will replace the entire image's alpha which turns the rest of the circle image's transparency white.
Is there a way for me to do this transparency "Merge" to achieve an alpha layer that is a composite of both images?
#image2 is a square, image1 is a circle
# swapTransparency is a function I made that works in swapping the transparency, it just goes pixel by pixel and switches alpha channel value to # max where empty and to 0 everywhere else.
# probably a better and more effective way to invert the transparency but this works right now and might not even be needed.
def swapTransparency(img):
datas = img.getdata()
newData = []
for item in datas:
if item [3] == 0:
newData.append((0, 0, 0, 255))
else:
newData.append((255, 255, 255, 0))
img.putdata(newData)
return img
##This is putting alpha channel overtop but its replacing the entire alpha instead of merging them, losing original cricle transparency.
image2 = swapTransparency(image2)
alphaChannel = image2.getchannel('A')
image1.putalpha(image2)
Image1
Image2
Desired Results
I am rotating an image 45 degree. When I rotate the image it has a black border and the image size changes from 256x256 to 364x364. I want to remove the values of this black border and keep the size 256. In pillow if I put fill color then the black border will go away but the size is still the same. Is there any way that I can remove the black border and retain the original shape
code to rotate
path = "E:\\download\\1.jpeg"
image = cv2.imread(path)
rotated = imutils.rotate_bound(image, -33)
Original Image
Rotate image
Keeping the shape while rotating an image is simply not possible in the way you want to. Just like rotating a square-shaped sheet of paper, the horizontal width would enlarge when rotating by e.g. 45°. If you now crop the image on 256x256, you would obtain again black area in the image (see example below). So you would have too crop it even more or zoom in then.
you can try to crop the image as much as part of the image you want. Although the cropping in python is possible in the form of pixels. Hence, you can try to crop the image as much is required.
The following code might help you to crop
im=Image.open(r"specify the path of the image")`
width, height = im.size
left = "specify the value in pixels"
top = "specify the value in pixels"
right = "specify the value in pixels"
bottom = "specify the value in pixels"
# Cropped image of above dimension
# (It will not change original image)
im1 = im.crop((left, top, right, bottom))
#im1.show()
im1.save('specify destination path')
I need a bright version of some of my images in pygame. However, I don't want to make a bright version of every single one. Can I change this through pygame?
I've found a similar queation here (How can you edit the brightness of images in PyGame?), but I don't know how to multiply the color of an image. Can someone explain how I can do that?
If you want to brighten an image, then I recommend to add a constant color to the surface. This can be achieved by .fill(), wby the use of the special parameter BLEND_RGB_ADD. If the fill color is black (0, 0, 0) then the image won't change at all. If the fill color is white (255, 255, 255), then the entire image will become white. e.g.:
image = pygame.image.load(my_imagename)
brighten = 128
image.fill((brighten, brighten, brighten), special_flags=pygame.BLEND_RGB_ADD)
[...] I want the image to be more transparent.
If you want to increase the transparency of the image, then yo can "blend" the image with a transparent color, by the use of the special flag BLEND_RGBA_MULT . Of course you've to ensure that the image format provides an alpha channel (e.g. .convert_alpha())
image = pygame.image.load(my_imagename).convert_alpha()
transparency = 128
image.fill((255, 255, 255, transparency), special_flags=pygame.BLEND_RGBA_MULT)
I want to rotate a black and white image. I am trying to use the rotate function as follows:
image.rotate(angle, fillcolor=255)
I am required to older versions of Python and Pillow, and they do not support the 'fillcolor' argument. I cannot upgrade to the newer versions due to certain restrictions and cannot use any external libraries.
Is there another way to fill the area outside the rotated image with white color using Pillow?
Rotated image has black color in the area outside the rotated part. I want to fill it with white color.
Original : Original image
Rotated :Rotated image
You can try Interpolating the Original Image, with the cropped one via Image.composite() to get rid of the black bars/borders.
from PIL import Image
img = Image.open(r"Image_Path").convert("RGBA")
angle = 30
img = img.rotate(angle)
new_img = Image.new('RGBA', img.size, 'white')
Alpha_Image = Image.composite(img, new_img, img)
Alpha_Image = Alpha_Image.convert(img.mode)
Alpha_Image.show()
The above code takes in an Image, converts it into mode RGBA (Alpha is required for this process), and then rotates the Image by 30 degrees. After that It creates a empty Image object of mode RGBA of the same dimensions as the original image, with each pixel having a default value of 255 each channel (i.e Pure white for RGB, and Full Opacity in the context of Alpha/Transparency). Then Interpolates the original image with this empty one using the mask of original Image (we are using the transparency mask of the first image). This results in the Desired images, where black bars/edges are replaced by white. In the end we convert the image color space to the original one.
ORIGINAL IMAGE:-
IMAGE AFTER ROTATING 30 DEGREES:-
An awkward option that has always worked for me, seeing as with my tools I always get a light gray "border" around the rotated image that interferes with filling:
add a border on the non-rotated image and use the fill color with that border.
The bordering operation is lossless and filling will be exact (and easy).
rotate the bordered image. The seam will now also be correct (but not exact unless you
rotate by 45° or 90°).
calculate the size of the rotated border using trigonometry. The result will not be exact (i.e. "131.12 pixel"). Usually you can do this in reverse, starting with an exact border on the rotated image and calculating the border you need to add, and adjust the border width so that the nonrotated border is exact. Example: with a rotated border of 170 pixels you get a nonrotated border of 140.3394 pixels. So you use a 510 pixel rotated border, resulting in the need to add a 421.018 pixel nonrotated border. This is close enough to 421 pixels that it is acceptable.
remove the rotated border.
This also helps avoiding some artefacts near the cut parts of the image that fall off the rotated image.
It has the drawback that you end up with a more massive rotation, with higher memory expenditure and computation time, especially if you use larger borders to increase precision.
Edit: As no external libraries are allowed, I would suggest cropping the rectangle you want and pasting it onto the original image, this could be done with magic numbers (of the rectangle's coordinates), this works for me (you might will need to tweek a little)
im = Image.open("mFul4.png")
rotated = im.rotate(105)
box = (55, 65,200,210)
d = rotated.crop(box=box)
im.paste(d, box=box)
im.save("ex.bmp" )
and the output
Edit2: This is the ugliest way, but it works, you might need to tweak the magic numbers a bit to have it more precise, I was working on your given image, so couldn't tell when i'm overdoing it. It produces the same output
from PIL import Image
im = Image.open("mFul4.png")
angle=105
cos = 0.240959049 # -cos(angle)
d = im.rotate(angle)
pix = d.load()
tri_x = 120
for i in range(4): # 4 triangles
for j in range(tri_x, -1, -1):
for k in range(int((tri_x-j)*cos)+1, -1, -1):
x,y =( j, k )if i <1 else (d.size[0]-j-1, d.size[1]-k-1)
if i in [2,3]:
y, x = (d.size[0] - j-2 , k) if i <3 else (j, d.size[1] - k)
pix[x,y] = (255, 255, 255, 255)
d.show()
I am trying to combine three images together. The image I want on the bottom is a 700x900 image with all black pixels. On top of that I want to paste an image that is 400x400 with an offset of 100,200. On top of that I want to paste an image border that is 700x900. The image border has alpha=0 in the inside of it and alpha=0 around it because it doesn't have straight edges. When I run the code I have pasted below I encounter 2 problems:
1) Everywhere on the border image where the alpha channel = 0, the alpha channel has been set to 255 and the color white shows instead of the black background and the image I am putting the border around.
2) The border image's quality has been significantly reduced and looks a lot different than it should.
Also: part of the border image will cover part of the Image I am putting the border around. So I can't just switch the order that I am pasting.
Thanks in advance for any help.
#!/usr/bin/python -tt
from PIL import ImageTk, Image
old_im2 = Image.open('backgroundImage1.jpg') # size = 400x400
old_im = Image.open('topImage.png') # size = 700x900
new_size = (700,900)
new_im = Image.new("RGBA", new_size) # makes the black image
new_im.paste(old_im2, (100, 200))
new_im.paste(old_im,(0,0))
new_im.show()
new_im.save('final.jpg')
I think you have a misconception about images - the border image does have pixels everywhere. It's not possible for it to be "missing" pixels. It is possible to have an image with an alpha channel, which is a channel like the R, G, and B channels, but indicates transparency.
Try this:
1. Make sure that topImage.png has a transparency channel, and that the pixels that you want to be "missing" are transparent (i.e. have a maximum alpha value). You can double check this way:
print old_im.mode # This should print "RGBA" if it has an alpha channel.
2. Create new_im in "RGBA" mode:
new_im = Image.new("RGBA", new_size) # makes the black image
# Note the "A" --------^
3. Try this paste statement instead:
new_im.paste(old_im,(0,0), mask=old_im) # Using old_im as the mask argument should tell the paste function to use old_im's alpha channel to combine the two images.