I am trying to input an image (image1) and flip it horizontally and then save to a file (image2). This works but not the way I want it to
currently this code gives me a flipped image but it just shows the bottom right quarter of the image, so it is the wrong size. Am I overwriting something somewhere? I just want the code to flip the image horizontally and show the whole picture flipped. Where did I go wrong?
and I cannot just use a mirror function or reverse function, I need to write an algorithm
I get the correct window size but the incorrect image size
def Flip(image1, image2):
img = graphics.Image(graphics.Point(0, 0), image1)
X, Y = img.getWidth(), img.getHeight()
for y in range(Y):
for x in range(X):
r, g, b = img.getPixel(x,y)
color = graphics.color_rgb(r, g, b)
img.setPixel(X-x, y, color)
win = graphics.GraphWin(img, img.getWidth(), img.getHeight())
img.draw(win)
img.save(image2)
I think your problem is in this line:
win = graphics.GraphWin(img, img.getWidth(), img.getHeight())
The first argument to the GraphWin constructor is supposed to be the title, but you are instead giving it an Image object. It makes me believe that maybe the width and height you are supplying are then being ignored. The default width and height for GraphWin is 200 x 200, so depending on the size of your image, that may be why only part of it is being drawn.
Try something like this:
win = graphics.GraphWin("Flipping an Image", img.getWidth(), img.getHeight())
Another problem is that your anchor point for the image is wrong. According to the docs, the anchor point is where the center of the image will be rendered (thus at 0,0 you are only seeing the bottom right quadrant of the picture). Here is a possible solution if you don't know what the size of the image is at the time of creation:
img = graphics.Image(graphics.Point(0, 0), image1)
img.move(img.getWidth() / 2, img.getHeight() / 2)
You are editing your source image. It would be
better to create an image copy and set those pixels instead:
create a new image for editing:
img_new = img
Assign the pixel values to that:
img_new.setPixel(X-x, y, color)
And draw that instead:
win = graphics.GraphWin(img_new, img_new.getWidth(), img_new.getHeight())
img_new.draw(win)
img_new.save(image2)
This will also check that your ranges are correct. if they are not, you will see both flipped and unflipped portions in the final image, showing which portions are outside of your ranges.
If you're not opposed to using an external library, I'd recommend the Python Imaging Library. In particular, the ImageOps module has a mirror function that should do exactly what you want.
Related
My use case :
I want to add a border of 10 pixel to the image using the ImageOps.expand method in the PIL. It asks for a fill value the default being black.
I researched and found that in order to find the color value of a pixel,
you need to do
pix = im.load()
im = ImageOps.expand(im, border=10, fill=pix[0,0])
Issue:
I am not able to pass this pix[x,y] value to the expand method. I went through the method definition and can't find the exact reason this is failing. This is the official documentation of the PIL that asks you to send a fill value.
I am able to get this kind of image. The only thing that is wrong is the annoying white border even though i am using the fill value as pix[0,0].
The following works for me:
from PIL import Image, ImageOps
img = Image.open('skooter.png')
x, y = 0, 0
pix = img.load()
img2 = ImageOps.expand(img, border=10, fill=pix[x,y])
img2.show()
Result:
I'm working on a game and I have some problems working with images.
I have loaded a few images . loading them and using screen.blit() was okay like below:
img1 = pygame.image.load("leaf.png")
img1 = pygame.transform.scale(img1, (25,25))
leaf = img1.get_rect()
leaf.x = random.randint(0, 570)
leaf.y = random.randint(0, 570)
but I don't know how to remove them in an if statement like this for example:
if count == 1:
...
and I though maybe there is no way and I should draw a rectangle on the image to disappear it. Also I don't know how to use screen.fill() while I don't want the other images to get disappeared. Is there any other way?
You can fill individual images, since they are pygame Surfaces.
First, what I would do is I would put something like this after defining the leaf's x/y:
leaf.image = img1
Then, I would create a color variable called transparent:
transparent = (0, 0, 0, 0)
The first 3 numbers, as you might know, represent RGB color values. The last number is the alpha (transparency) value of a color. 0 is completely invisible.
Finally, I would add this code to make the leaf completely transparent:
leaf.image.fill(transparent)
This makes the leaf transparent without making every other image in your window disappear. Hope this helped!
Basically, I have two images. One is comprised of white and black pixels, the black pixels making up a word, and the other image that I'm trying to paste the black pixels on top of. I've pasted the code below, however I'm aware that there's an issue with the "if pixels [x,y] == (0, 0, 0):' being a tuple and not an indice, however I'm uncertain of how to get it to look for black pixels with other means.
So essentially I need to find, and remember the positions of, the black pixels so that I can paste them onto the first image. Any help is very much appreciated!
image_one = Image.open (image_one)
image_two = Image.open (image_two)
pixels = list(image_two.getdata())
for y in xrange(image_two.size[1]):
for x in xrange(image_two.size[0]):
if pixels[x,y] == (0, 0, 0):
pixels = black_pixels
black_pixels.append()
image = Image.open (image_one);
image_one.putdata(pixels)
image.save(image_one+ "_X.bmp")
del image_one, image_two;
You're almost there. I am not too familiar with the PIL class, but instead of calling the getdata method, let's use getpixel directly on the image object, and directly set the results into the output image. That eliminates the need to store the set of pixels to overwrite. However, there may be cases beyond what you've listed here where such an approach would be necessary. I created a random image and then set various pixels to black. For this test I used a different condition - if the R channel of the image is greater than 50. You can comment that out and use the other test, which tests for tuple (R,G,B) == (0,0,0) which will work fine.
imagea = PIL.Image.open('temp.png')
imageb = PIL.Image.open('temp.png')
for y in xrange(imagea.size[1]):
for x in xrange(imagea.size[0]):
currentPixel = imagea.getpixel((x,y))
if currentPixel[0] > 50:
#if currentPixel ==(0,0,0):
#this is a black pixel, you can directly modify image 2 now
imageb.putpixel((x,y),(0,0,0))
imageb.save('outputfile.png')
An alternative way to do this is just to multiply the two images together. Any pixel that's black in the binary image will be black in the result (multiply by zero) and any pixel that's white in the binary image will be unchanged from the other image in the result (multiply by one).
PIL can do this,
from PIL import Image, ImageChops
image_one = Image.open("image_one.bmp")
image_two = Image.open("image_two.bmp")
out = ImageChops.multiply(image_one, image_two)
out.save("output.bmp")
I'm using PIL.
im = im.rotate(angle=-90, expand = True)
When I do this, it adds a greyish border to my image.
Why?
Here's m full code. Note that if I don't rotate, it adds no borders
def fixRotation(f, quality=96, image_type="JPEG"):
#http://sylvana.net/jpegcrop/exif_orientation.html
d =getEXIF(f)
if d:
orientation = int(d['Orientation'])
im = Image.open(StringIO(f))
if orientation == 6:
im = im.rotate(angle=-90, expand = True)
elif orientation == 3:
im = im.rotate(angle=-180, expand=True)
elif orientation == 8:
im = im.rotate(angle=-270, expand=True)
else:
#It doesn't add a border here.
im = im.rotate(0, expand=True)
res = StringIO()
im.save(res, image_type, quality=quality)
res.seek(0)
return res
else:
return StringIO(f)
I made some experiment and indeed image size is altered but I didn't understad the exact behavior. To me looks like a bug in PIL... you should report it.
If you only need k*90 degrees then to do the rotation you can also use numpy...
img = Image.fromarray(numpy.rot90(numpy.array(img), n))
n is the number of times to rotate by 90 degrees.
Note the following (CPython 2.6, PIL 1.1.7):
import Image
i= Image.open("someimage.jpg")
ir0= i.rotate(-90)
ir1= i.rotate(-90, expand=1)
for img in i, ir0, ir1:
print(img.size)
# output follows
(720, 400)
(400, 720)
(401, 721)
When the angle is a multiple of 90, expand is not needed.
expand in the case of right-angle multiples seems to activate a bug
So, if all you care about is 90°-180°-270° rotations, just drop the expand=1 argument; even better, use the transpose method (see Geometrical Transforms in the PIL tutorial )
When rotating, the algorithm (essentially) averages each pixel with the "next" pixel value. For all pixels "inside" the image, the next pixel is defined. For all pixels at the edge of the image, that pixel is undefined.
So the grey is the average between the known perimeter pixel and an undefined exterior pixel.
I've been making a picture mirroring in horizontal and vertical axes. Now I'm going to make the diagonal.
I had done the hori and verti width two for loops which in the hori scenario loops through all the pixels in the height and only the half of the pixels in the width. Then it gets the color of the pixel and set the same color to the pixel on the other side. Going from the getWidth(pic) to the center.
Then I have my mirror in the middle of the pic. How to do the diagonal way?
Edit:
img_src = makePicture(pickAFile())
W = getWidth(img_src)
H = getHeight(img_src)
for x in range(W):
for y in range(H):
p = getPixel(img_src, x, y)
colorInSrc = getColor( getPixel(img_src, x, y) )
destPixel = getPixel(img_src, H-y-1, W-x-1)
setColor(destPixel, colorInSrc)
Using PIL (the Python Imaging Library) this is a relatively straightforward task. Notice however, that the output image is square -- thus not the same size as the original image.
Here is the code:
from PIL import Image, ImageDraw
# load the image, create the mirrored image, and the result placeholder
img = Image.open('img.png')
mirror = img.transpose(Image.FLIP_LEFT_RIGHT).transpose(Image.ROTATE_90)
sz = max(img.size + mirror.size)
result = Image.new(img.mode, (sz,sz))
result.paste(img, (0,0)+img.size)
# now paste the mirrored image, but with a triangular binary mask
mask = Image.new('1', mirror.size)
draw = ImageDraw.Draw(mask)
draw.polygon([0,0,0,sz,sz,sz], outline='white', fill='white')
result.paste(mirror, (0,0)+mirror.size, mask)
# clean up and save the result
del mirror, mask, draw
result.save('result.png')
If I understood correctly what you need is to "flip" the image by a diagonal. Since there are two of them I'll presume that you mean the one that goes from left bottom to right top.
In order to flip by this diagonal you need to transform each row from the source in columns in the destination. The left part of the rows will become the bottom part of the new columns. Also the topmost row will become the rightmost column. You will need to do this pixel by pixel on the whole image. Also keep in mind that the width and height of the image will be swapped.
Edit: A small example. Say you start with an image 5 pixels wide and 3 pixels high (5x3). You will need to create a new blank image 3 pixels wide and 5 pixels high.
If you start pixel numbering from left top corner with (0,0), then this pixel will end up at (2,4) in the new image, pixel (1,0) will end at (2,3) and so on.
If your original width and height are W and H then you should use something like this:
for x in xrange(W):
for y in xrange(H):
p = img_src.getpixel(x, y)
img_dest.setpixel(H-y-1, W-x-1)
This should work, but is not tested.
It's not really an Python question, is it?
The easiest solution would be to first mirror horizontal and then vertical.
Another one would be to switch pixel rows with columns.
Or to do your algorithm but switch the pixels from left-top to bottom-right...
Here's how to mirror diagonally in JES; It only works for a square image though:
def mirrorDiagonal(picture):
for sourceX in range(0,getWidth(picture)):
for sourceY in range (0,getHeight(picture)):
pex=getPixel(picture,sourceY,sourceX)
pix=getPixel(picture, sourceX,sourceY)
color=getColor(pix)
setColor(pex,color)
show(picture)